[VOL-1349] EPON OLT adapter (package B)

Change-Id: I634ef62c53813dcf4456f54948f13e06358e263c
diff --git a/internal/pkg/core/l2oam/common.go b/internal/pkg/core/l2oam/common.go
new file mode 100644
index 0000000..b77cf3d
--- /dev/null
+++ b/internal/pkg/core/l2oam/common.go
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//Package l2oam Common Logger initialization
+package l2oam
+
+import (
+	"context"
+	"fmt"
+	"time"
+)
+
+//var logger log.CLogger
+var logger l2OAMLogger
+
+// func init() {
+// 	// Setup this package so that it's log level can be modified at run time
+// 	var err error
+// 	logger, err = log.RegisterPackage(log.JSON, log.ErrorLevel, log.Fields{})
+// 	if err != nil {
+// 		panic(err)
+// 	}
+// }
+
+func init() {
+	logger = l2OAMLogger{}
+	logger.Debug(context.Background(), "initialize l2oam logger")
+}
+
+//l2OAMLogger ...
+type l2OAMLogger struct {
+}
+
+//Debug ...
+func (l *l2OAMLogger) Debug(ctx context.Context, message string) {
+	fmt.Printf("%v:%s\n", time.Now(), message)
+}
diff --git a/internal/pkg/core/l2oam/message.go b/internal/pkg/core/l2oam/message.go
new file mode 100644
index 0000000..dd092da
--- /dev/null
+++ b/internal/pkg/core/l2oam/message.go
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"net"
+	"sync"
+
+	"github.com/google/gopacket"
+	"github.com/google/gopacket/layers"
+)
+
+// OnuPkgType describes target package type
+var OnuPkgType = "PkgB"
+
+// OnuPkgTypeA is a constant of package
+const OnuPkgTypeA = "PkgA"
+
+// OnuPkgTypeB is a constant of package
+const OnuPkgTypeB = "PkgB"
+
+// TibitFrame is a typical structure of a frame
+type TibitFrame struct {
+	layers.BaseLayer
+	Data []byte
+}
+
+// LayerType returns ethernet layer type
+func (t *TibitFrame) LayerType() gopacket.LayerType { return layers.LayerTypeEthernet }
+
+// SerializeTo serializes a data structure to byte arrays
+func (t *TibitFrame) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
+	length := len(t.Data)
+	bytes, err := b.PrependBytes(length)
+	if err != nil {
+		return err
+	}
+	copy(bytes, t.Data)
+	return nil
+}
+
+// TomiObjectContext is a structure for tomi object
+type TomiObjectContext struct {
+	Branch   uint8
+	Type     uint16
+	Length   uint8
+	Instance uint32
+}
+
+// CreateMessage creates l2 message
+func CreateMessage(srcMac string, dstMac string, ethernetType layers.EthernetType, tibitData gopacket.SerializableLayer) []byte {
+	srcMAC, _ := net.ParseMAC(srcMac)
+	dstMAC, _ := net.ParseMAC(dstMac)
+
+	ethernetLayer := &layers.Ethernet{
+		SrcMAC:       srcMAC,
+		DstMAC:       dstMAC,
+		EthernetType: ethernetType,
+	}
+
+	buf := gopacket.NewSerializeBuffer()
+	if err := gopacket.SerializeLayers(
+		buf,
+		gopacket.SerializeOptions{
+			ComputeChecksums: true,
+			FixLengths:       true,
+		},
+		ethernetLayer,
+		tibitData,
+	); err != nil {
+		return buf.Bytes()
+	}
+	return buf.Bytes()
+}
+
+// CreateMessage creates vlan message
+func CreateMessageVlan(srcMac string, dstMac string, ethernetType layers.EthernetType, tibitData gopacket.SerializableLayer, vlanLayer *layers.Dot1Q) []byte {
+	srcMAC, _ := net.ParseMAC(srcMac)
+	dstMAC, _ := net.ParseMAC(dstMac)
+
+	ethernetLayer := &layers.Ethernet{
+		SrcMAC:       srcMAC,
+		DstMAC:       dstMAC,
+		EthernetType: ethernetType,
+	}
+
+	buf := gopacket.NewSerializeBuffer()
+	if err := gopacket.SerializeLayers(
+		buf,
+		gopacket.SerializeOptions{
+			ComputeChecksums: true,
+			FixLengths:       true,
+		},
+		ethernetLayer,
+		vlanLayer,
+		tibitData,
+	); err != nil {
+		return buf.Bytes()
+	}
+	return buf.Bytes()
+}
+
+// CorrelationTag instance ID
+// It is incremented automatically for each TOMI message with OLT
+var instance uint32 = 0x5c1f6a60
+var instanceMutex sync.Mutex
+
+func getOltInstance() uint32 {
+	instanceMutex.Lock()
+	defer instanceMutex.Unlock()
+	instance = instance + 1
+
+	return instance
+
+}
diff --git a/internal/pkg/core/l2oam/msg_after_keep_alive.go b/internal/pkg/core/l2oam/msg_after_keep_alive.go
new file mode 100644
index 0000000..4772e11
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_after_keep_alive.go
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+package l2oam
+
+import (
+	"encoding/binary"
+
+	"github.com/google/gopacket"
+)
+
+func GeneratePcscompuTibitcom() gopacket.SerializableLayer {
+
+	data := &TibitFrame{
+		Data: []byte{0x03, 0x00, 0x50, 0xfe, 0x2a, 0xea, 0x15, 0x01, 0x0c, 0x0c, 0x7a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x11, 0x04, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x07, 0x00, 0x00},
+	}
+
+	binary.BigEndian.PutUint32(data.Data[12:16], getOltInstance())
+
+	return data
+
+}
diff --git a/internal/pkg/core/l2oam/msg_autonomous.go b/internal/pkg/core/l2oam/msg_autonomous.go
new file mode 100644
index 0000000..dff723d
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_autonomous.go
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"encoding/hex"
+	"fmt"
+
+	"github.com/google/gopacket"
+	"github.com/google/gopacket/layers"
+)
+
+// AutonomousEvent is a structure for Autonomous Event
+type AutonomousEvent struct {
+	ComResp TOAMGetResponse
+	EcLength  uint8
+	EcValue   []byte
+	EndBranch uint8
+}
+
+// String returns the string expression of AutonomousEvent
+func (d *AutonomousEvent) String() string {
+	message := d.ComResp.String()
+	message = fmt.Sprintf("%s, EcLength:%v, EcValue:%v, EndBranch:%v", message, d.EcLength, hex.EncodeToString(d.EcValue), d.EndBranch)
+	return message
+}
+
+// Len returns the length of AutonomousEvent
+func (d *AutonomousEvent) Len() int {
+	return d.ComResp.Len() + int(d.ComResp.VcLength) + 1
+}
+
+// LayerType returns the ethernet type of AutonomousEvent
+func (d *AutonomousEvent) LayerType() gopacket.LayerType { return layers.LayerTypeEthernet }
+
+// SerializeTo serializes a data structure to byte arrays
+func (d *AutonomousEvent) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
+	return nil
+}
+
+// Decode decodes byte arrays to a data structure
+func (d *AutonomousEvent) Decode(data []byte) error {
+	d.ComResp.Decode(data)
+	i := d.ComResp.Len()
+	d.EcLength = data[i]
+	i++
+	d.EcValue = data[i : i+int(d.EcLength)]
+	i = i + int(d.EcLength)
+	d.EndBranch = data[i]
+
+	return nil
+}
+
+// IsRegistrationStatusMessage returns true if the message is for ONU registration
+func (d *AutonomousEvent) IsRegistrationStatusMessage() bool {
+	return d.ComResp.VcBranch == 0x01 && d.ComResp.VcLeaf == 0x0009
+}
diff --git a/internal/pkg/core/l2oam/msg_best_effort_mbs.go b/internal/pkg/core/l2oam/msg_best_effort_mbs.go
new file mode 100644
index 0000000..fe63edf
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_best_effort_mbs.go
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GenerateBestEffortMbs generates "Traffic Profile/Best Effort MBS" message
+func GenerateBestEffortMbs() gopacket.SerializableLayer {
+
+	tibitData := &TOAMSetRequest{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OAM Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBit OLT Management Interface
+		TOMIOpcode: 0x03,
+		// Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		// Object Context
+		OCBranch:   0x0c,
+		OCType:     0x070f,
+		OCLength:   4,
+		OCInstance: 0x00000002,
+		// Vc
+		VcBranch: 0x7f,
+		VcLeaf:   0x0009,
+		VcLength: 5,
+		// EC
+		ECLength: 4,
+		ECValue:  []byte{0x00, 0x06, 0x40, 0x00},
+		// End
+		EndBranch: 0x00,
+	}
+	return tibitData
+}
diff --git a/internal/pkg/core/l2oam/msg_best_effort_rate.go b/internal/pkg/core/l2oam/msg_best_effort_rate.go
new file mode 100644
index 0000000..42ccd43
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_best_effort_rate.go
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"encoding/binary"
+
+	"github.com/google/gopacket"
+)
+
+// GenerateBestEffortRate generates "Traffic Profile/Best Effort Rate" message
+func GenerateBestEffortRate(ecvalue []byte, trafficProfile []byte) gopacket.SerializableLayer {
+
+	tibitData := &TOAMSetRequest{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OAM Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBit OLT Management Interface
+		TOMIOpcode: 0x03,
+		// Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		// Object Context
+		OCBranch:   0x0c,
+		OCType:     0x070f,
+		OCLength:   4,
+		OCInstance: binary.BigEndian.Uint32(trafficProfile),
+		// Vc
+		VcBranch: 0x7f,
+		VcLeaf:   0x0008,
+		VcLength: uint8(1 + len(ecvalue)), //5
+		// EC
+		ECLength: uint8(len(ecvalue)), //4
+		ECValue:  ecvalue,             //[]byte{0x00, 0x4c, 0x4b, 0x40}
+		// End
+		EndBranch: 0x00,
+	}
+	return tibitData
+}
diff --git a/internal/pkg/core/l2oam/msg_best_effort_rate_test.go b/internal/pkg/core/l2oam/msg_best_effort_rate_test.go
new file mode 100644
index 0000000..25bfb49
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_best_effort_rate_test.go
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package l2oam
+
+import (
+	"encoding/binary"
+	"reflect"
+	"testing"
+
+	"github.com/google/gopacket"
+)
+
+func TestGenerateBestEffortRate(t *testing.T) {
+	type args struct {
+		ecvalue        []byte
+		trafficProfile []byte
+	}
+	tests := []struct {
+		name string
+		args args
+		want gopacket.SerializableLayer
+	}{
+		// TODO: Add test cases.
+		{
+			name: "GenerateBestEffortRate-1",
+			args: args{
+				ecvalue:        []byte{0x00, 0x4c, 0x4b, 0x40},
+				trafficProfile: []byte{0x00, 0x00, 0x00, 0x01},
+			},
+			want: &TOAMSetRequest{
+				// IEEE 1904.2
+				Opcode: 0x03,
+				// OAM Protocol
+				Flags:      0x0050,
+				OAMPDUCode: 0xfe,
+				OUId:       []byte{0x2a, 0xea, 0x15},
+				// TiBit OLT Management Interface
+				TOMIOpcode: 0x03,
+				// Correlation Tag
+				CTBranch:   0x0c,
+				CTType:     0x0c7a,
+				CTLength:   4,
+				CTInstance: getOltInstance() + 1,
+				// Object Context
+				OCBranch:   0x0c,
+				OCType:     0x070f,
+				OCLength:   4,
+				OCInstance: binary.BigEndian.Uint32([]byte{0x00, 0x00, 0x00, 0x01}),
+				// Vc
+				VcBranch: 0x7f,
+				VcLeaf:   0x0008,
+				VcLength: 5, //5
+				// EC
+				ECLength: 4,                              //4
+				ECValue:  []byte{0x00, 0x4c, 0x4b, 0x40}, //[]byte{0x00, 0x4c, 0x4b, 0x40}
+				// End
+				EndBranch: 0x00,
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := GenerateBestEffortRate(tt.args.ecvalue, tt.args.trafficProfile); !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("GenerateBestEffortRate() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
diff --git a/internal/pkg/core/l2oam/msg_discovery.go b/internal/pkg/core/l2oam/msg_discovery.go
new file mode 100644
index 0000000..ab104bc
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_discovery.go
@@ -0,0 +1,396 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"encoding/binary"
+	"encoding/hex"
+	"fmt"
+
+	"github.com/google/gopacket"
+	"github.com/google/gopacket/layers"
+)
+
+// GenerateDiscoverySOLICIT generates "Discovery: SOLICIT" message
+func GenerateDiscoverySOLICIT() gopacket.SerializableLayer {
+
+	tibitData := &DiscoverySolicit{
+		// IEEE 1904.2
+		Opcode:        0xfd,
+		DiscoveryType: 0x01,
+		// Vendor-specific
+		VendorType: 0xfe,
+		Length:     37,
+		// Vendor ID
+		VendorIDType:   0xfd,
+		VendorIDLength: 3,
+		VendorID:       []byte{0x2a, 0xea, 0x15},
+		// Controller Priority
+		CPType:   0x05,
+		CPLength: 1,
+		CPValue:  []byte{128},
+		//NetworkID
+		NWType:   0x06,
+		NWLength: 16,
+		NWValue:  []byte("tibitcom.com"),
+		//Device Type
+		DVType:   0x07,
+		DVLength: 1,
+		DVValue:  []byte{1},
+		//Supported CLient Protocols
+		SCPType:   0x08,
+		SCPLength: 1,
+		SCPValue:  []byte{0x03},
+		//Padding
+		PadType:   0xff,
+		PadLength: 1,
+		PadValue:  []byte{0},
+	}
+
+	return tibitData
+}
+
+// DiscoverySolicit is a structure for Discovery message
+type DiscoverySolicit struct {
+	layers.BaseLayer
+	Opcode        uint8
+	DiscoveryType uint8
+	VendorType uint8
+	Length     uint16 // length of after this data without Padding
+	VendorIDType   uint8
+	VendorIDLength uint16
+	VendorID       []byte
+	CPType   uint8
+	CPLength uint16
+	CPValue  []byte
+	NWType   uint8
+	NWLength uint16
+	NWValue  []byte
+	DVType   uint8
+	DVLength uint16
+	DVValue  []byte
+	SCPType   uint8
+	SCPLength uint16
+	SCPValue  []byte
+	PadType   uint8
+	PadLength uint16
+	PadValue  []byte
+}
+
+// String returns the string expression of DiscoverySolicit
+func (d *DiscoverySolicit) String() string {
+	message := fmt.Sprintf("Opcode:%v, DiscoveryType:%v, VendorType:%v, Length:%v", d.Opcode, d.DiscoveryType, d.VendorType, d.Length)
+	message = fmt.Sprintf("%s, VendorIDType:%v, VendorIDLength:%v, VendorID:%v", message, d.VendorIDType, d.VendorIDLength, hex.EncodeToString(d.VendorID))
+	message = fmt.Sprintf("%s, CPType:%v, CPLength:%v, CPValue:%v", message, d.CPType, d.CPLength, hex.EncodeToString(d.CPValue))
+	message = fmt.Sprintf("%s, NWType:%v, NWLength:%v, NWValue:%v", message, d.NWType, d.NWLength, hex.EncodeToString(d.NWValue))
+	message = fmt.Sprintf("%s, DVType:%v, DVLength:%v, DVValue:%v", message, d.DVType, d.DVLength, hex.EncodeToString(d.DVValue))
+	message = fmt.Sprintf("%s, SCPType:%v, SCPLength:%v, SCPValue:%v", message, d.SCPType, d.SCPLength, hex.EncodeToString(d.SCPValue))
+	return message
+}
+
+// Len returns the length of DiscoverySolicit
+func (d *DiscoverySolicit) Len() int {
+	len := (2) + (3) + int(d.Length) + (int(d.PadLength) + 3)
+	return len
+}
+
+// LayerType returns the ethernet type of DiscoverySolicit
+func (d *DiscoverySolicit) LayerType() gopacket.LayerType { return layers.LayerTypeEthernet }
+
+// SerializeTo serializes a data structure to byte arrays
+func (d *DiscoverySolicit) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
+	plen := int(d.Len())
+	data, err := b.PrependBytes(plen)
+	if err != nil {
+		return err
+	}
+
+	i := 0
+	data[i] = byte(d.Opcode)
+	i++
+	data[i] = byte(d.DiscoveryType)
+	i++
+	data[i] = byte(d.VendorType)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.Length)
+	i = i + 2
+
+	data[i] = byte(d.VendorIDType)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.VendorIDLength)
+	i = i + 2
+	copy(data[i:i+int(d.VendorIDLength)], d.VendorID)
+	i = i + int(d.VendorIDLength)
+
+	data[i] = byte(d.CPType)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.CPLength)
+	i = i + 2
+	copy(data[i:i+int(d.CPLength)], d.CPValue)
+	i = i + int(d.CPLength)
+
+	data[i] = byte(d.NWType)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.NWLength)
+	i = i + 2
+	copy(data[i:i+int(d.NWLength)], d.NWValue)
+	i = i + int(d.NWLength)
+
+	data[i] = byte(d.DVType)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.DVLength)
+	i = i + 2
+	copy(data[i:i+int(d.DVLength)], d.DVValue)
+	i = i + int(d.DVLength)
+
+	data[i] = byte(d.SCPType)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.SCPLength)
+	i = i + 2
+	copy(data[i:i+int(d.SCPLength)], d.SCPValue)
+	i = i + int(d.SCPLength)
+
+	data[i] = byte(d.PadType)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.PadLength)
+	i = i + 2
+	copy(data[i:i+int(d.PadLength)], d.PadValue)
+
+	return nil
+}
+
+// Decode decodes byte arrays to a data structure
+func (d *DiscoverySolicit) Decode(data []byte) error {
+	i := 0
+	d.Opcode = data[i]
+	i++
+	d.DiscoveryType = data[i]
+	i++
+	d.VendorType = data[i]
+	i++
+	d.Length = binary.BigEndian.Uint16(data[i : i+2])
+	i = i + 2
+
+	d.VendorIDType = data[i]
+	i++
+	d.VendorIDLength = binary.BigEndian.Uint16(data[i : i+2])
+	i = i + 2
+	d.VendorID = data[i : i+int(d.VendorIDLength)]
+	i = i + int(d.VendorIDLength)
+
+	d.CPType = data[i]
+	i++
+	d.CPLength = binary.BigEndian.Uint16(data[i : i+2])
+	i = i + 2
+	d.CPValue = data[i : i+int(d.CPLength)]
+	i = i + int(d.CPLength)
+
+	d.NWType = data[i]
+	i++
+	d.NWLength = binary.BigEndian.Uint16(data[i : i+2])
+	i = i + 2
+	d.NWValue = data[i : i+int(d.NWLength)]
+	i = i + int(d.NWLength)
+
+	d.DVType = data[i]
+	i++
+	d.DVLength = binary.BigEndian.Uint16(data[i : i+2])
+	i = i + 2
+	d.DVValue = data[i : i+int(d.DVLength)]
+	i = i + int(d.DVLength)
+
+	d.SCPType = data[i]
+	i++
+	d.SCPLength = binary.BigEndian.Uint16(data[i : i+2])
+	i = i + 2
+	d.SCPValue = data[i : i+int(d.SCPLength)]
+	i = i + int(d.SCPLength)
+
+	d.PadType = data[i]
+	i++
+	d.PadLength = binary.BigEndian.Uint16(data[i : i+2])
+	i = i + 2
+	d.PadValue = data[i : i+int(d.PadLength)]
+
+	return nil
+}
+
+// DiscoveryHello is a structure for Discovery message
+type DiscoveryHello struct {
+	layers.BaseLayer
+	Opcode        uint8
+	DiscoveryType uint8
+	VendorType uint8
+	Length     uint16 // length of after this data without Padding
+	VendorIDType   uint8
+	VendorIDLength uint16
+	VendorID       []byte
+	NWType   uint8
+	NWLength uint16
+	NWValue  []byte
+	DVType   uint8
+	DVLength uint16
+	DVValue  []byte
+	SCPType   uint8
+	SCPLength uint16
+	SCPValue  []byte
+	TunnelType   uint8
+	TunnelLength uint16
+	TunnelValue  []byte
+	PadType   uint8
+	PadLength uint16
+	PadValue  []byte
+}
+
+// String returns the string expression of DiscoveryHello
+func (d *DiscoveryHello) String() string {
+	message := fmt.Sprintf("Opcode:%v, DiscoveryType:%v, VendorType:%v, Length:%v", d.Opcode, d.DiscoveryType, d.VendorType, d.Length)
+	message = fmt.Sprintf("%s, VendorIDType:%v, VendorIDLength:%v, VendorID:%v", message, d.VendorIDType, d.VendorIDLength, hex.EncodeToString(d.VendorID))
+	message = fmt.Sprintf("%s, NWType:%v, NWLength:%v, NWValue:%v", message, d.NWType, d.NWLength, hex.EncodeToString(d.NWValue))
+	message = fmt.Sprintf("%s, DVType:%v, DVLength:%v, DVValue:%v", message, d.DVType, d.DVLength, hex.EncodeToString(d.DVValue))
+	message = fmt.Sprintf("%s, SCPType:%v, SCPLength:%v, SCPValue:%v", message, d.SCPType, d.SCPLength, hex.EncodeToString(d.SCPValue))
+	message = fmt.Sprintf("%s, TunnelType:%v, TunnelLength:%v, TunnelValue:%v", message, d.TunnelType, d.TunnelLength, hex.EncodeToString(d.TunnelValue))
+	message = fmt.Sprintf("%s, PadType:%v, PadLength:%v, PadValue:%v", message, d.PadType, d.PadLength, hex.EncodeToString(d.PadValue))
+	return message
+}
+
+// Len returns the length of DiscoveryHello
+func (d *DiscoveryHello) Len() int {
+	len := (2) + (3) + int(d.Length) + (int(d.PadLength) + 3)
+	return len
+}
+
+// LayerType returns the ethernet type of DiscoveryHello
+func (d *DiscoveryHello) LayerType() gopacket.LayerType { return layers.LayerTypeEthernet }
+
+// SerializeTo serializes a data structure to byte arrays
+func (d *DiscoveryHello) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
+	plen := int(d.Len())
+	data, err := b.PrependBytes(plen)
+	if err != nil {
+		return err
+	}
+
+	i := 0
+	data[i] = byte(d.Opcode)
+	i++
+	data[i] = byte(d.DiscoveryType)
+	i++
+	data[i] = byte(d.VendorType)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.Length)
+	i = i + 2
+
+	data[i] = byte(d.VendorIDType)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.VendorIDLength)
+	i = i + 2
+	copy(data[i:i+int(d.VendorIDLength)], d.VendorID)
+	i = i + int(d.VendorIDLength)
+
+	data[i] = byte(d.NWType)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.NWLength)
+	i = i + 2
+	copy(data[i:i+int(d.NWLength)], d.NWValue)
+	i = i + int(d.NWLength)
+
+	data[i] = byte(d.DVType)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.DVLength)
+	i = i + 2
+	copy(data[i:i+int(d.DVLength)], d.DVValue)
+	i = i + int(d.DVLength)
+
+	data[i] = byte(d.SCPType)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.SCPLength)
+	i = i + 2
+	copy(data[i:i+int(d.SCPLength)], d.SCPValue)
+	i = i + int(d.SCPLength)
+
+	data[i] = byte(d.TunnelType)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.TunnelLength)
+	i = i + 2
+	copy(data[i:i+int(d.TunnelLength)], d.TunnelValue)
+	i = i + int(d.TunnelLength)
+
+	data[i] = byte(d.PadType)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.PadLength)
+	i = i + 2
+	copy(data[i:i+int(d.PadLength)], d.PadValue)
+
+	return nil
+}
+
+// Decode decodes byte arrays to a data structure
+func (d *DiscoveryHello) Decode(data []byte) error {
+	i := 0
+	d.Opcode = data[i]
+	i++
+	d.DiscoveryType = data[i]
+	i++
+	d.VendorType = data[i]
+	i++
+	d.Length = binary.BigEndian.Uint16(data[i : i+2])
+	i = i + 2
+
+	d.VendorIDType = data[i]
+	i++
+	d.VendorIDLength = binary.BigEndian.Uint16(data[i : i+2])
+	i = i + 2
+	d.VendorID = data[i : i+int(d.VendorIDLength)]
+	i = i + int(d.VendorIDLength)
+
+	d.NWType = data[i]
+	i++
+	d.NWLength = binary.BigEndian.Uint16(data[i : i+2])
+	i = i + 2
+	d.NWValue = data[i : i+int(d.NWLength)]
+	i = i + int(d.NWLength)
+
+	d.DVType = data[i]
+	i++
+	d.DVLength = binary.BigEndian.Uint16(data[i : i+2])
+	i = i + 2
+	d.DVValue = data[i : i+int(d.DVLength)]
+	i = i + int(d.DVLength)
+
+	d.SCPType = data[i]
+	i++
+	d.SCPLength = binary.BigEndian.Uint16(data[i : i+2])
+	i = i + 2
+	d.SCPValue = data[i : i+int(d.SCPLength)]
+	i = i + int(d.SCPLength)
+
+	d.TunnelType = data[i]
+	i++
+	d.TunnelLength = binary.BigEndian.Uint16(data[i : i+2])
+	i = i + 2
+	d.TunnelValue = data[i : i+int(d.TunnelLength)]
+	i = i + int(d.TunnelLength)
+
+	d.PadType = data[i]
+	i++
+	d.PadLength = binary.BigEndian.Uint16(data[i : i+2])
+	i = i + 2
+	d.PadValue = data[i : i+int(d.PadLength)]
+
+	return nil
+}
diff --git a/internal/pkg/core/l2oam/msg_discovery_test.go b/internal/pkg/core/l2oam/msg_discovery_test.go
new file mode 100644
index 0000000..618c81a
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_discovery_test.go
@@ -0,0 +1,1409 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package l2oam
+
+import (
+	"encoding/binary"
+	"encoding/hex"
+	"fmt"
+	"reflect"
+	"testing"
+
+	"github.com/google/gopacket"
+	"github.com/google/gopacket/layers"
+)
+
+func TestGenerateDiscoverySOLICIT(t *testing.T) {
+	tests := []struct {
+		name string
+		want gopacket.SerializableLayer
+	}{
+		// TODO: Add test cases.
+		{
+			name: "GenerateDiscoverySOLICIT-1",
+			want: &DiscoverySolicit{
+				// IEEE 1904.2
+				Opcode:        0xfd,
+				DiscoveryType: 0x01,
+				// Vendor-specific
+				VendorType: 0xfe,
+				Length:     37,
+				// Vendor ID
+				VendorIDType:   0xfd,
+				VendorIDLength: 3,
+				VendorID:       []byte{0x2a, 0xea, 0x15},
+				// Controller Priority
+				CPType:   0x05,
+				CPLength: 1,
+				CPValue:  []byte{128},
+				//NetworkID
+				NWType:   0x06,
+				NWLength: 16,
+				NWValue:  []byte("tibitcom.com"),
+				//Device Type
+				DVType:   0x07,
+				DVLength: 1,
+				DVValue:  []byte{1},
+				//Supported CLient Protocols
+				SCPType:   0x08,
+				SCPLength: 1,
+				SCPValue:  []byte{0x03},
+				//Padding
+				PadType:   0xff,
+				PadLength: 1,
+				PadValue:  []byte{0},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := GenerateDiscoverySOLICIT(); !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("GenerateDiscoverySOLICIT() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestDiscoverySolicit_String(t *testing.T) {
+	type fields struct {
+		BaseLayer      layers.BaseLayer
+		Opcode         uint8
+		DiscoveryType  uint8
+		VendorType     uint8
+		Length         uint16
+		VendorIDType   uint8
+		VendorIDLength uint16
+		VendorID       []byte
+		CPType         uint8
+		CPLength       uint16
+		CPValue        []byte
+		NWType         uint8
+		NWLength       uint16
+		NWValue        []byte
+		DVType         uint8
+		DVLength       uint16
+		DVValue        []byte
+		SCPType        uint8
+		SCPLength      uint16
+		SCPValue       []byte
+		PadType        uint8
+		PadLength      uint16
+		PadValue       []byte
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		want   string
+	}{
+		// TODO: Add test cases.
+		{
+			name: "String-1",
+			fields: fields{
+				// IEEE 1904.2
+				Opcode:        0xfd,
+				DiscoveryType: 0x01,
+				// Vendor-specific
+				VendorType: 0xfe,
+				Length:     37,
+				// Vendor ID
+				VendorIDType:   0xfd,
+				VendorIDLength: 3,
+				VendorID:       []byte{0x2a, 0xea, 0x15},
+				// Controller Priority
+				CPType:   0x05,
+				CPLength: 1,
+				CPValue:  []byte{128},
+				//NetworkID
+				NWType:   0x06,
+				NWLength: 16,
+				NWValue:  []byte("tibitcom.com"),
+				//Device Type
+				DVType:   0x07,
+				DVLength: 1,
+				DVValue:  []byte{1},
+				//Supported CLient Protocols
+				SCPType:   0x08,
+				SCPLength: 1,
+				SCPValue:  []byte{0x03},
+				//Padding
+				PadType:   0xff,
+				PadLength: 1,
+				PadValue:  []byte{0},
+			},
+			want: fmt.Sprintf("Opcode:253, DiscoveryType:1, VendorType:254, Length:37, VendorIDType:253, VendorIDLength:3, VendorID:2aea15, CPType:5, CPLength:1, CPValue:80, NWType:6, NWLength:16, NWValue:%v, DVType:7, DVLength:1, DVValue:01, SCPType:8, SCPLength:1, SCPValue:03", hex.EncodeToString([]byte("tibitcom.com"))),
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			d := &DiscoverySolicit{
+				BaseLayer:      tt.fields.BaseLayer,
+				Opcode:         tt.fields.Opcode,
+				DiscoveryType:  tt.fields.DiscoveryType,
+				VendorType:     tt.fields.VendorType,
+				Length:         tt.fields.Length,
+				VendorIDType:   tt.fields.VendorIDType,
+				VendorIDLength: tt.fields.VendorIDLength,
+				VendorID:       tt.fields.VendorID,
+				CPType:         tt.fields.CPType,
+				CPLength:       tt.fields.CPLength,
+				CPValue:        tt.fields.CPValue,
+				NWType:         tt.fields.NWType,
+				NWLength:       tt.fields.NWLength,
+				NWValue:        tt.fields.NWValue,
+				DVType:         tt.fields.DVType,
+				DVLength:       tt.fields.DVLength,
+				DVValue:        tt.fields.DVValue,
+				SCPType:        tt.fields.SCPType,
+				SCPLength:      tt.fields.SCPLength,
+				SCPValue:       tt.fields.SCPValue,
+				PadType:        tt.fields.PadType,
+				PadLength:      tt.fields.PadLength,
+				PadValue:       tt.fields.PadValue,
+			}
+			if got := d.String(); got != tt.want {
+				t.Errorf("DiscoverySolicit.String() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestDiscoverySolicit_Len(t *testing.T) {
+	type fields struct {
+		BaseLayer      layers.BaseLayer
+		Opcode         uint8
+		DiscoveryType  uint8
+		VendorType     uint8
+		Length         uint16
+		VendorIDType   uint8
+		VendorIDLength uint16
+		VendorID       []byte
+		CPType         uint8
+		CPLength       uint16
+		CPValue        []byte
+		NWType         uint8
+		NWLength       uint16
+		NWValue        []byte
+		DVType         uint8
+		DVLength       uint16
+		DVValue        []byte
+		SCPType        uint8
+		SCPLength      uint16
+		SCPValue       []byte
+		PadType        uint8
+		PadLength      uint16
+		PadValue       []byte
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		want   int
+	}{
+		// TODO: Add test cases.
+		{
+			name: "Len-1",
+			fields: fields{
+				// IEEE 1904.2
+				Opcode:        0xfd,
+				DiscoveryType: 0x01,
+				// Vendor-specific
+				VendorType: 0xfe,
+				Length:     37,
+				// Vendor ID
+				VendorIDType:   0xfd,
+				VendorIDLength: 3,
+				VendorID:       []byte{0x2a, 0xea, 0x15},
+				// Controller Priority
+				CPType:   0x05,
+				CPLength: 1,
+				CPValue:  []byte{128},
+				//NetworkID
+				NWType:   0x06,
+				NWLength: 16,
+				NWValue:  []byte("tibitcom.com"),
+				//Device Type
+				DVType:   0x07,
+				DVLength: 1,
+				DVValue:  []byte{1},
+				//Supported CLient Protocols
+				SCPType:   0x08,
+				SCPLength: 1,
+				SCPValue:  []byte{0x03},
+				//Padding
+				PadType:   0xff,
+				PadLength: 1,
+				PadValue:  []byte{0},
+			},
+			want: 46,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			d := &DiscoverySolicit{
+				BaseLayer:      tt.fields.BaseLayer,
+				Opcode:         tt.fields.Opcode,
+				DiscoveryType:  tt.fields.DiscoveryType,
+				VendorType:     tt.fields.VendorType,
+				Length:         tt.fields.Length,
+				VendorIDType:   tt.fields.VendorIDType,
+				VendorIDLength: tt.fields.VendorIDLength,
+				VendorID:       tt.fields.VendorID,
+				CPType:         tt.fields.CPType,
+				CPLength:       tt.fields.CPLength,
+				CPValue:        tt.fields.CPValue,
+				NWType:         tt.fields.NWType,
+				NWLength:       tt.fields.NWLength,
+				NWValue:        tt.fields.NWValue,
+				DVType:         tt.fields.DVType,
+				DVLength:       tt.fields.DVLength,
+				DVValue:        tt.fields.DVValue,
+				SCPType:        tt.fields.SCPType,
+				SCPLength:      tt.fields.SCPLength,
+				SCPValue:       tt.fields.SCPValue,
+				PadType:        tt.fields.PadType,
+				PadLength:      tt.fields.PadLength,
+				PadValue:       tt.fields.PadValue,
+			}
+			if got := d.Len(); got != tt.want {
+				t.Errorf("DiscoverySolicit.Len() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestDiscoverySolicit_LayerType(t *testing.T) {
+	type fields struct {
+		BaseLayer      layers.BaseLayer
+		Opcode         uint8
+		DiscoveryType  uint8
+		VendorType     uint8
+		Length         uint16
+		VendorIDType   uint8
+		VendorIDLength uint16
+		VendorID       []byte
+		CPType         uint8
+		CPLength       uint16
+		CPValue        []byte
+		NWType         uint8
+		NWLength       uint16
+		NWValue        []byte
+		DVType         uint8
+		DVLength       uint16
+		DVValue        []byte
+		SCPType        uint8
+		SCPLength      uint16
+		SCPValue       []byte
+		PadType        uint8
+		PadLength      uint16
+		PadValue       []byte
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		want   gopacket.LayerType
+	}{
+		// TODO: Add test cases.
+		{
+			name: "LayerType-1",
+			want: layers.LayerTypeEthernet,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			d := &DiscoverySolicit{
+				BaseLayer:      tt.fields.BaseLayer,
+				Opcode:         tt.fields.Opcode,
+				DiscoveryType:  tt.fields.DiscoveryType,
+				VendorType:     tt.fields.VendorType,
+				Length:         tt.fields.Length,
+				VendorIDType:   tt.fields.VendorIDType,
+				VendorIDLength: tt.fields.VendorIDLength,
+				VendorID:       tt.fields.VendorID,
+				CPType:         tt.fields.CPType,
+				CPLength:       tt.fields.CPLength,
+				CPValue:        tt.fields.CPValue,
+				NWType:         tt.fields.NWType,
+				NWLength:       tt.fields.NWLength,
+				NWValue:        tt.fields.NWValue,
+				DVType:         tt.fields.DVType,
+				DVLength:       tt.fields.DVLength,
+				DVValue:        tt.fields.DVValue,
+				SCPType:        tt.fields.SCPType,
+				SCPLength:      tt.fields.SCPLength,
+				SCPValue:       tt.fields.SCPValue,
+				PadType:        tt.fields.PadType,
+				PadLength:      tt.fields.PadLength,
+				PadValue:       tt.fields.PadValue,
+			}
+			if got := d.LayerType(); !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("DiscoverySolicit.LayerType() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestDiscoverySolicit_SerializeTo(t *testing.T) {
+	type fields struct {
+		BaseLayer      layers.BaseLayer
+		Opcode         uint8
+		DiscoveryType  uint8
+		VendorType     uint8
+		Length         uint16
+		VendorIDType   uint8
+		VendorIDLength uint16
+		VendorID       []byte
+		CPType         uint8
+		CPLength       uint16
+		CPValue        []byte
+		NWType         uint8
+		NWLength       uint16
+		NWValue        []byte
+		DVType         uint8
+		DVLength       uint16
+		DVValue        []byte
+		SCPType        uint8
+		SCPLength      uint16
+		SCPValue       []byte
+		PadType        uint8
+		PadLength      uint16
+		PadValue       []byte
+	}
+	type args struct {
+		b    gopacket.SerializeBuffer
+		opts gopacket.SerializeOptions
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+	}{
+		// TODO: Add test cases.
+		{
+			name: "SerializeTo-1",
+			fields: fields{
+				// IEEE 1904.2
+				Opcode:        0xfd,
+				DiscoveryType: 0x01,
+				// Vendor-specific
+				VendorType: 0xfe,
+				Length:     37,
+				// Vendor ID
+				VendorIDType:   0xfd,
+				VendorIDLength: 3,
+				VendorID:       []byte{0x2a, 0xea, 0x15},
+				// Controller Priority
+				CPType:   0x05,
+				CPLength: 1,
+				CPValue:  []byte{128},
+				//NetworkID
+				NWType:   0x06,
+				NWLength: 16,
+				NWValue:  []byte("tibitcom.com"),
+				//Device Type
+				DVType:   0x07,
+				DVLength: 1,
+				DVValue:  []byte{1},
+				//Supported CLient Protocols
+				SCPType:   0x08,
+				SCPLength: 1,
+				SCPValue:  []byte{0x03},
+				//Padding
+				PadType:   0xff,
+				PadLength: 1,
+				PadValue:  []byte{0},
+			},
+			args: args{
+				b:    gopacket.NewSerializeBufferExpectedSize(0, 36),
+				opts: gopacket.SerializeOptions{},
+			},
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			d := &DiscoverySolicit{
+				BaseLayer:      tt.fields.BaseLayer,
+				Opcode:         tt.fields.Opcode,
+				DiscoveryType:  tt.fields.DiscoveryType,
+				VendorType:     tt.fields.VendorType,
+				Length:         tt.fields.Length,
+				VendorIDType:   tt.fields.VendorIDType,
+				VendorIDLength: tt.fields.VendorIDLength,
+				VendorID:       tt.fields.VendorID,
+				CPType:         tt.fields.CPType,
+				CPLength:       tt.fields.CPLength,
+				CPValue:        tt.fields.CPValue,
+				NWType:         tt.fields.NWType,
+				NWLength:       tt.fields.NWLength,
+				NWValue:        tt.fields.NWValue,
+				DVType:         tt.fields.DVType,
+				DVLength:       tt.fields.DVLength,
+				DVValue:        tt.fields.DVValue,
+				SCPType:        tt.fields.SCPType,
+				SCPLength:      tt.fields.SCPLength,
+				SCPValue:       tt.fields.SCPValue,
+				PadType:        tt.fields.PadType,
+				PadLength:      tt.fields.PadLength,
+				PadValue:       tt.fields.PadValue,
+			}
+			if err := d.SerializeTo(tt.args.b, tt.args.opts); (err != nil) != tt.wantErr {
+				t.Errorf("DiscoverySolicit.SerializeTo error = %v, wantErr %v", err, tt.wantErr)
+			}
+
+			data := tt.args.b.Bytes()
+			cnt := 0
+			digits := 0
+			if !reflect.DeepEqual(d.Opcode, data[cnt]) {
+				t.Error("DiscoverySolicit.SerializeTo Opcode error")
+			}
+			cnt++
+			if !reflect.DeepEqual(d.DiscoveryType, data[cnt]) {
+				t.Error("DiscoverySolicit.SerializeTo DiscoveryType error")
+			}
+			cnt++
+			if !reflect.DeepEqual(d.VendorType, data[cnt]) {
+				t.Error("DiscoverySolicit.SerializeTo VendorType error")
+			}
+			cnt++
+
+			if !reflect.DeepEqual(d.Length, binary.BigEndian.Uint16(data[cnt:cnt+2])) {
+				t.Error("DiscoverySolicit.SerializeTo Length error")
+			}
+			cnt += 2
+
+			if !reflect.DeepEqual(d.VendorIDType, data[cnt]) {
+				t.Error("DiscoverySolicit.SerializeTo VendorIDType error")
+			}
+			cnt++
+			if !reflect.DeepEqual(d.VendorIDLength, binary.BigEndian.Uint16(data[cnt:cnt+2])) {
+				t.Error("DiscoverySolicit.SerializeTo VendorIDLength error")
+			}
+			cnt += 2
+			digits = int(d.VendorIDLength)
+			if !reflect.DeepEqual(d.VendorID, data[cnt:cnt+digits]) {
+				t.Error("DiscoverySolicit.SerializeTo VendorID error")
+			}
+			cnt += digits
+			if !reflect.DeepEqual(d.CPType, data[cnt]) {
+				t.Error("DiscoverySolicit.SerializeTo CPType error")
+			}
+			cnt++
+			if !reflect.DeepEqual(d.CPLength, binary.BigEndian.Uint16(data[cnt:cnt+2])) {
+				t.Error("DiscoverySolicit.SerializeTo CPLength error")
+			}
+			cnt += 2
+			digits = int(d.CPLength)
+			if !reflect.DeepEqual(d.CPValue, data[cnt:cnt+digits]) {
+				t.Error("DiscoverySolicit.SerializeTo CPValue error")
+			}
+			cnt += digits
+			if !reflect.DeepEqual(d.NWType, data[cnt]) {
+				t.Error("DiscoverySolicit.SerializeTo NWType error")
+			}
+			cnt++
+			if !reflect.DeepEqual(d.NWLength, binary.BigEndian.Uint16(data[cnt:cnt+2])) {
+				t.Error("DiscoverySolicit.SerializeTo NWLength error")
+			}
+			cnt += 2
+			//digits = int(d.NWLength)
+			for _, dvalue := range d.NWValue {
+				if !reflect.DeepEqual(dvalue, data[cnt]) {
+					t.Error("DiscoverySolicit.SerializeTo NWValue error")
+				}
+				cnt++
+			}
+			// if !reflect.DeepEqual(string(d.NWValue), string(data[cnt:cnt+digits])) {
+			// 	t.Errorf("DiscoverySolicit.SerializeTo NWValue error %x %x", d.NWValue, data[cnt:cnt+digits])
+			// }
+			cnt += 4
+			if !reflect.DeepEqual(d.DVType, data[cnt]) {
+				t.Error("DiscoverySolicit.SerializeTo DVType error")
+			}
+			cnt++
+			if !reflect.DeepEqual(d.DVLength, binary.BigEndian.Uint16(data[cnt:cnt+2])) {
+				t.Error("DiscoverySolicit.SerializeTo DVLength error")
+			}
+			cnt += 2
+			digits = int(d.DVLength)
+			if !reflect.DeepEqual(d.DVValue, data[cnt:cnt+digits]) {
+				t.Error("DiscoverySolicit.SerializeTo DVValue error")
+			}
+			cnt += digits
+			if !reflect.DeepEqual(d.SCPType, data[cnt]) {
+				t.Error("DiscoverySolicit.SerializeTo SCPType error")
+			}
+			cnt++
+			if !reflect.DeepEqual(d.SCPLength, binary.BigEndian.Uint16(data[cnt:cnt+2])) {
+				t.Error("DiscoverySolicit.SerializeTo SCPLength error")
+			}
+			cnt += 2
+			digits = int(d.SCPLength)
+			if !reflect.DeepEqual(d.SCPValue, data[cnt:cnt+digits]) {
+				t.Error("DiscoverySolicit.SerializeTo SCPValue error")
+			}
+			cnt += digits
+			if !reflect.DeepEqual(d.PadType, data[cnt]) {
+				t.Error("DiscoverySolicit.SerializeTo PadType error")
+			}
+			cnt++
+			if !reflect.DeepEqual(d.PadLength, binary.BigEndian.Uint16(data[cnt:cnt+2])) {
+				t.Error("DiscoverySolicit.SerializeTo PadLength error")
+			}
+			cnt += 2
+			digits = int(d.PadLength)
+			if !reflect.DeepEqual(d.PadValue, data[cnt:cnt+digits]) {
+				t.Error("DiscoverySolicit.SerializeTo PadValue error")
+			}
+
+		})
+	}
+}
+
+func TestDiscoverySolicit_Decode(t *testing.T) {
+	type fields struct {
+		BaseLayer      layers.BaseLayer
+		Opcode         uint8
+		DiscoveryType  uint8
+		VendorType     uint8
+		Length         uint16
+		VendorIDType   uint8
+		VendorIDLength uint16
+		VendorID       []byte
+		CPType         uint8
+		CPLength       uint16
+		CPValue        []byte
+		NWType         uint8
+		NWLength       uint16
+		NWValue        []byte
+		DVType         uint8
+		DVLength       uint16
+		DVValue        []byte
+		SCPType        uint8
+		SCPLength      uint16
+		SCPValue       []byte
+		PadType        uint8
+		PadLength      uint16
+		PadValue       []byte
+	}
+	type args struct {
+		data []byte
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+	}{
+		// TODO: Add test cases.
+		{
+			name: "Decode-1",
+			args: args{
+				data: []byte{0xfd, 0x01, 0xfe, 0x00, 0x25, 0xfd, 0x00, 0x03, 0x2a, 0xea, 0x15, 0x05, 0x00, 0x01, 0x80, 0x06, 0x00, 0x10, 0x74, 0x69, 0x62, 0x69, 0x74, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x01, 0x08, 0x00, 0x01, 0x03, 0xff, 0x00, 0x01, 0x00},
+			},
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			d := &DiscoverySolicit{
+				BaseLayer:      tt.fields.BaseLayer,
+				Opcode:         tt.fields.Opcode,
+				DiscoveryType:  tt.fields.DiscoveryType,
+				VendorType:     tt.fields.VendorType,
+				Length:         tt.fields.Length,
+				VendorIDType:   tt.fields.VendorIDType,
+				VendorIDLength: tt.fields.VendorIDLength,
+				VendorID:       tt.fields.VendorID,
+				CPType:         tt.fields.CPType,
+				CPLength:       tt.fields.CPLength,
+				CPValue:        tt.fields.CPValue,
+				NWType:         tt.fields.NWType,
+				NWLength:       tt.fields.NWLength,
+				NWValue:        tt.fields.NWValue,
+				DVType:         tt.fields.DVType,
+				DVLength:       tt.fields.DVLength,
+				DVValue:        tt.fields.DVValue,
+				SCPType:        tt.fields.SCPType,
+				SCPLength:      tt.fields.SCPLength,
+				SCPValue:       tt.fields.SCPValue,
+				PadType:        tt.fields.PadType,
+				PadLength:      tt.fields.PadLength,
+				PadValue:       tt.fields.PadValue,
+			}
+			if err := d.Decode(tt.args.data); (err != nil) != tt.wantErr {
+				t.Errorf("DiscoverySolicit.Decode error = %v, wantErr %v", err, tt.wantErr)
+			}
+
+			cnt := 0
+			digits := 0
+
+			if !reflect.DeepEqual(d.Opcode, tt.args.data[cnt]) {
+				t.Errorf("DiscoverySolicit.Decode Opcode error Opcode=%x,data=%x,cnt=%x", d.Opcode, tt.args.data[cnt:], cnt)
+			}
+			cnt++
+			if !reflect.DeepEqual(d.DiscoveryType, tt.args.data[cnt]) {
+				t.Errorf("DiscoverySolicit.Decode DiscoveryType error DiscoveryType=%X data=%x", d.DiscoveryType, tt.args.data[cnt:cnt+1])
+			}
+			cnt++
+			if !reflect.DeepEqual(d.VendorType, tt.args.data[cnt]) {
+				t.Errorf("DiscoverySolicit.Decode VendorType error %x %x", tt.args.data[cnt], d.VendorType)
+			}
+			cnt++
+
+			if !reflect.DeepEqual(d.Length, binary.BigEndian.Uint16(tt.args.data[cnt:cnt+2])) {
+				t.Errorf("DiscoverySolicit.Decode Length error Length=%x data[cnt:cnt+2]=%x", string(d.Length), string(binary.BigEndian.Uint16(tt.args.data[cnt:cnt+2])))
+			}
+			cnt += 2
+
+			if !reflect.DeepEqual(d.VendorIDType, tt.args.data[cnt]) {
+				t.Errorf("DiscoverySolicit.Decode VendorIDType error VendorIDType=%x data=%x", d.VendorIDType, tt.args.data[cnt])
+			}
+			cnt++
+			if !reflect.DeepEqual(d.VendorIDLength, binary.BigEndian.Uint16(tt.args.data[cnt:cnt+2])) {
+				t.Errorf("DiscoverySolicit.Decode VendorIDLength error VendorIDLength=%x data[cnt:cnt+2]=%x", d.VendorIDLength, tt.args.data[cnt:cnt+2])
+			}
+			cnt += 2
+			digits = int(d.VendorIDLength)
+			if !reflect.DeepEqual(d.VendorID, tt.args.data[cnt:cnt+digits]) {
+				t.Errorf("DiscoverySolicit.Decode VendorID error %v %v", d.VendorID, tt.args.data[cnt:cnt+3])
+			}
+			cnt += digits
+			if !reflect.DeepEqual(d.CPType, tt.args.data[cnt]) {
+				t.Error("DiscoverySolicit.Decode CPType error")
+			}
+			cnt++
+			if !reflect.DeepEqual(d.CPLength, binary.BigEndian.Uint16(tt.args.data[cnt:cnt+2])) {
+				t.Error("DiscoverySolicit.Decode CPLength error")
+			}
+			cnt += 2
+			digits = int(d.CPLength)
+			if !reflect.DeepEqual(d.CPValue, tt.args.data[cnt:cnt+digits]) {
+				t.Errorf("DiscoverySolicit.Decode CPValue error %x %x", tt.args.data[14:15], d.CPValue)
+			}
+			cnt += digits
+			if !reflect.DeepEqual(d.NWType, tt.args.data[cnt]) {
+				t.Error("DiscoverySolicit.Decode NWType error")
+			}
+			cnt++
+			if !reflect.DeepEqual(d.NWLength, binary.BigEndian.Uint16(tt.args.data[cnt:cnt+2])) {
+				t.Error("DiscoverySolicit.Decode NWLength error")
+			}
+			cnt += 2
+			//digits = int(d.NWLength)
+			for _, dvalue := range d.NWValue {
+				if !reflect.DeepEqual(dvalue, tt.args.data[cnt]) {
+					t.Errorf("DiscoverySolicit.Decode NWValue error %x %x", dvalue, tt.args.data[cnt])
+				}
+				cnt++
+			}
+			// if !reflect.DeepEqual(string(d.NWValue), string(tt.args.data[cnt:cnt+digits])) {
+			// 	t.Errorf("DiscoverySolicit.Decode NWValue error %x %x", d.NWValue, tt.args.data[cnt:cnt+digits])
+			// }
+			// cnt += 4
+			if !reflect.DeepEqual(d.DVType, tt.args.data[cnt]) {
+				t.Errorf("DiscoverySolicit.Decode DVType error %x %x", d.DVType, tt.args.data[cnt])
+			}
+			cnt++
+			if !reflect.DeepEqual(d.DVLength, binary.BigEndian.Uint16(tt.args.data[cnt:cnt+2])) {
+				t.Errorf("DiscoverySolicit.Decode DVLength error %x %x", d.DVLength, tt.args.data[cnt:cnt+2])
+			}
+			cnt += 2
+			digits = int(d.DVLength)
+			if !reflect.DeepEqual(d.DVValue, tt.args.data[cnt:cnt+digits]) {
+				t.Errorf("DiscoverySolicit.Decode DVValue error %x %x", d.DVValue, tt.args.data[cnt:cnt+digits])
+			}
+			cnt += digits
+			if !reflect.DeepEqual(d.SCPType, tt.args.data[cnt]) {
+				t.Errorf("DiscoverySolicit.Decode SCPType error %x %x", d.SCPType, tt.args.data[cnt])
+			}
+			cnt++
+			if !reflect.DeepEqual(d.SCPLength, binary.BigEndian.Uint16(tt.args.data[cnt:cnt+2])) {
+				t.Error("DiscoverySolicit.Decode SCPLength error")
+			}
+			cnt += 2
+			digits = int(d.SCPLength)
+			if !reflect.DeepEqual(d.SCPValue, tt.args.data[cnt:cnt+digits]) {
+				t.Errorf("DiscoverySolicit.Decode SCPValue error cnt= %x digits=%x", cnt, digits)
+			}
+			cnt += digits
+			if !reflect.DeepEqual(d.PadType, tt.args.data[cnt]) {
+				t.Error("DiscoverySolicit.Decode PadType error")
+			}
+			cnt++
+			if !reflect.DeepEqual(d.PadLength, binary.BigEndian.Uint16(tt.args.data[cnt:cnt+2])) {
+				t.Error("DiscoverySolicit.Decode PadLength error")
+			}
+			cnt += 2
+			digits = int(d.PadLength)
+			if !reflect.DeepEqual(d.PadValue, tt.args.data[cnt:cnt+digits]) {
+				t.Errorf("DiscoverySolicit.Decode PadValue error %x %x", d.PadValue, tt.args.data[cnt:cnt+digits])
+			}
+
+		})
+	}
+}
+
+func TestDiscoveryHello_String(t *testing.T) {
+	type fields struct {
+		BaseLayer      layers.BaseLayer
+		Opcode         uint8
+		DiscoveryType  uint8
+		VendorType     uint8
+		Length         uint16
+		VendorIDType   uint8
+		VendorIDLength uint16
+		VendorID       []byte
+		NWType         uint8
+		NWLength       uint16
+		NWValue        []byte
+		DVType         uint8
+		DVLength       uint16
+		DVValue        []byte
+		SCPType        uint8
+		SCPLength      uint16
+		SCPValue       []byte
+		TunnelType     uint8
+		TunnelLength   uint16
+		TunnelValue    []byte
+		PadType        uint8
+		PadLength      uint16
+		PadValue       []byte
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		want   string
+	}{
+		// TODO: Add test cases.
+		{
+			name: "String-1",
+			fields: fields{
+				Opcode:         0xfd,
+				DiscoveryType:  0x01,
+				VendorType:     0xfe,
+				Length:         0x25,
+				VendorIDType:   0xfd,
+				VendorIDLength: 3,
+				VendorID:       []byte{0x2a, 0xea, 0x15},
+				NWType:         0x06,
+				NWLength:       16,
+				NWValue:        []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16},
+				DVType:         0x07,
+				DVLength:       1,
+				DVValue:        []byte{2},
+				SCPType:        0x08,
+				SCPLength:      1,
+				SCPValue:       []byte{0x03},
+				TunnelType:     0x0a,
+				TunnelLength:   2,
+				TunnelValue:    []byte{0x00, 0x01},
+				PadType:        0xff,
+				PadLength:      1,
+				PadValue:       []byte{0},
+			},
+			want: "Opcode:253, DiscoveryType:1, VendorType:254, Length:37, VendorIDType:253, VendorIDLength:3, VendorID:2aea15, NWType:6, NWLength:16, NWValue:01020304050607080910111213141516, DVType:7, DVLength:1, DVValue:02, SCPType:8, SCPLength:1, SCPValue:03, TunnelType:10, TunnelLength:2, TunnelValue:0001, PadType:255, PadLength:1, PadValue:00",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			d := &DiscoveryHello{
+				BaseLayer:      tt.fields.BaseLayer,
+				Opcode:         tt.fields.Opcode,
+				DiscoveryType:  tt.fields.DiscoveryType,
+				VendorType:     tt.fields.VendorType,
+				Length:         tt.fields.Length,
+				VendorIDType:   tt.fields.VendorIDType,
+				VendorIDLength: tt.fields.VendorIDLength,
+				VendorID:       tt.fields.VendorID,
+				NWType:         tt.fields.NWType,
+				NWLength:       tt.fields.NWLength,
+				NWValue:        tt.fields.NWValue,
+				DVType:         tt.fields.DVType,
+				DVLength:       tt.fields.DVLength,
+				DVValue:        tt.fields.DVValue,
+				SCPType:        tt.fields.SCPType,
+				SCPLength:      tt.fields.SCPLength,
+				SCPValue:       tt.fields.SCPValue,
+				TunnelType:     tt.fields.TunnelType,
+				TunnelLength:   tt.fields.TunnelLength,
+				TunnelValue:    tt.fields.TunnelValue,
+				PadType:        tt.fields.PadType,
+				PadLength:      tt.fields.PadLength,
+				PadValue:       tt.fields.PadValue,
+			}
+			if got := d.String(); got != tt.want {
+				t.Errorf("DiscoveryHello.String() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestDiscoveryHello_Len(t *testing.T) {
+	type fields struct {
+		BaseLayer      layers.BaseLayer
+		Opcode         uint8
+		DiscoveryType  uint8
+		VendorType     uint8
+		Length         uint16
+		VendorIDType   uint8
+		VendorIDLength uint16
+		VendorID       []byte
+		NWType         uint8
+		NWLength       uint16
+		NWValue        []byte
+		DVType         uint8
+		DVLength       uint16
+		DVValue        []byte
+		SCPType        uint8
+		SCPLength      uint16
+		SCPValue       []byte
+		TunnelType     uint8
+		TunnelLength   uint16
+		TunnelValue    []byte
+		PadType        uint8
+		PadLength      uint16
+		PadValue       []byte
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		want   int
+	}{
+		// TODO: Add test cases.
+		{
+			name: "Len-1",
+			fields: fields{
+				Opcode:         0xfd,
+				DiscoveryType:  0x01,
+				VendorType:     0xfe,
+				Length:         0x25,
+				VendorIDType:   0xfd,
+				VendorIDLength: 3,
+				VendorID:       []byte{0x2a, 0xea, 0x15},
+				NWType:         0x06,
+				NWLength:       16,
+				NWValue:        []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16},
+				DVType:         0x07,
+				DVLength:       1,
+				DVValue:        []byte{2},
+				SCPType:        0x08,
+				SCPLength:      1,
+				SCPValue:       []byte{0x03},
+				TunnelType:     0x0a,
+				TunnelLength:   2,
+				TunnelValue:    []byte{0x00, 0x01},
+				PadType:        0xff,
+				PadLength:      1,
+				PadValue:       []byte{0},
+			},
+			want: 46,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			d := &DiscoveryHello{
+				BaseLayer:      tt.fields.BaseLayer,
+				Opcode:         tt.fields.Opcode,
+				DiscoveryType:  tt.fields.DiscoveryType,
+				VendorType:     tt.fields.VendorType,
+				Length:         tt.fields.Length,
+				VendorIDType:   tt.fields.VendorIDType,
+				VendorIDLength: tt.fields.VendorIDLength,
+				VendorID:       tt.fields.VendorID,
+				NWType:         tt.fields.NWType,
+				NWLength:       tt.fields.NWLength,
+				NWValue:        tt.fields.NWValue,
+				DVType:         tt.fields.DVType,
+				DVLength:       tt.fields.DVLength,
+				DVValue:        tt.fields.DVValue,
+				SCPType:        tt.fields.SCPType,
+				SCPLength:      tt.fields.SCPLength,
+				SCPValue:       tt.fields.SCPValue,
+				TunnelType:     tt.fields.TunnelType,
+				TunnelLength:   tt.fields.TunnelLength,
+				TunnelValue:    tt.fields.TunnelValue,
+				PadType:        tt.fields.PadType,
+				PadLength:      tt.fields.PadLength,
+				PadValue:       tt.fields.PadValue,
+			}
+			if got := d.Len(); got != tt.want {
+				t.Errorf("DiscoveryHello.Len() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestDiscoveryHello_LayerType(t *testing.T) {
+	type fields struct {
+		BaseLayer      layers.BaseLayer
+		Opcode         uint8
+		DiscoveryType  uint8
+		VendorType     uint8
+		Length         uint16
+		VendorIDType   uint8
+		VendorIDLength uint16
+		VendorID       []byte
+		NWType         uint8
+		NWLength       uint16
+		NWValue        []byte
+		DVType         uint8
+		DVLength       uint16
+		DVValue        []byte
+		SCPType        uint8
+		SCPLength      uint16
+		SCPValue       []byte
+		TunnelType     uint8
+		TunnelLength   uint16
+		TunnelValue    []byte
+		PadType        uint8
+		PadLength      uint16
+		PadValue       []byte
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		want   gopacket.LayerType
+	}{
+		// TODO: Add test cases.
+		{
+			name: "LayerType-1",
+			want: layers.LayerTypeEthernet,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			d := &DiscoveryHello{
+				BaseLayer:      tt.fields.BaseLayer,
+				Opcode:         tt.fields.Opcode,
+				DiscoveryType:  tt.fields.DiscoveryType,
+				VendorType:     tt.fields.VendorType,
+				Length:         tt.fields.Length,
+				VendorIDType:   tt.fields.VendorIDType,
+				VendorIDLength: tt.fields.VendorIDLength,
+				VendorID:       tt.fields.VendorID,
+				NWType:         tt.fields.NWType,
+				NWLength:       tt.fields.NWLength,
+				NWValue:        tt.fields.NWValue,
+				DVType:         tt.fields.DVType,
+				DVLength:       tt.fields.DVLength,
+				DVValue:        tt.fields.DVValue,
+				SCPType:        tt.fields.SCPType,
+				SCPLength:      tt.fields.SCPLength,
+				SCPValue:       tt.fields.SCPValue,
+				TunnelType:     tt.fields.TunnelType,
+				TunnelLength:   tt.fields.TunnelLength,
+				TunnelValue:    tt.fields.TunnelValue,
+				PadType:        tt.fields.PadType,
+				PadLength:      tt.fields.PadLength,
+				PadValue:       tt.fields.PadValue,
+			}
+			if got := d.LayerType(); !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("DiscoveryHello.LayerType() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestDiscoveryHello_SerializeTo(t *testing.T) {
+	type fields struct {
+		BaseLayer      layers.BaseLayer
+		Opcode         uint8
+		DiscoveryType  uint8
+		VendorType     uint8
+		Length         uint16
+		VendorIDType   uint8
+		VendorIDLength uint16
+		VendorID       []byte
+		NWType         uint8
+		NWLength       uint16
+		NWValue        []byte
+		DVType         uint8
+		DVLength       uint16
+		DVValue        []byte
+		SCPType        uint8
+		SCPLength      uint16
+		SCPValue       []byte
+		TunnelType     uint8
+		TunnelLength   uint16
+		TunnelValue    []byte
+		PadType        uint8
+		PadLength      uint16
+		PadValue       []byte
+	}
+	type args struct {
+		b    gopacket.SerializeBuffer
+		opts gopacket.SerializeOptions
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+	}{
+		// TODO: Add test cases.
+		{
+			name: "SerializeTo-1",
+			fields: fields{
+				Opcode:         0xfd,
+				DiscoveryType:  0x01,
+				VendorType:     0xfe,
+				Length:         0x25,
+				VendorIDType:   0xfd,
+				VendorIDLength: 3,
+				VendorID:       []byte{0x2a, 0xea, 0x15},
+				NWType:         0x06,
+				NWLength:       16,
+				NWValue:        []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16},
+				DVType:         0x07,
+				DVLength:       1,
+				DVValue:        []byte{2},
+				SCPType:        0x08,
+				SCPLength:      1,
+				SCPValue:       []byte{0x03},
+				TunnelType:     0x0a,
+				TunnelLength:   2,
+				TunnelValue:    []byte{0x00, 0x01},
+				PadType:        0xff,
+				PadLength:      1,
+				PadValue:       []byte{0},
+			},
+			args: args{
+				b:    gopacket.NewSerializeBufferExpectedSize(0, 46),
+				opts: gopacket.SerializeOptions{},
+			},
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			d := &DiscoveryHello{
+				BaseLayer:      tt.fields.BaseLayer,
+				Opcode:         tt.fields.Opcode,
+				DiscoveryType:  tt.fields.DiscoveryType,
+				VendorType:     tt.fields.VendorType,
+				Length:         tt.fields.Length,
+				VendorIDType:   tt.fields.VendorIDType,
+				VendorIDLength: tt.fields.VendorIDLength,
+				VendorID:       tt.fields.VendorID,
+				NWType:         tt.fields.NWType,
+				NWLength:       tt.fields.NWLength,
+				NWValue:        tt.fields.NWValue,
+				DVType:         tt.fields.DVType,
+				DVLength:       tt.fields.DVLength,
+				DVValue:        tt.fields.DVValue,
+				SCPType:        tt.fields.SCPType,
+				SCPLength:      tt.fields.SCPLength,
+				SCPValue:       tt.fields.SCPValue,
+				TunnelType:     tt.fields.TunnelType,
+				TunnelLength:   tt.fields.TunnelLength,
+				TunnelValue:    tt.fields.TunnelValue,
+				PadType:        tt.fields.PadType,
+				PadLength:      tt.fields.PadLength,
+				PadValue:       tt.fields.PadValue,
+			}
+			if err := d.SerializeTo(tt.args.b, tt.args.opts); (err != nil) != tt.wantErr {
+				t.Errorf("DiscoveryHello.SerializeTo() error = %v, wantErr %v", err, tt.wantErr)
+			}
+
+			data := tt.args.b.Bytes()
+			cnt := 0
+			digits := 0
+			if !reflect.DeepEqual(d.Opcode, data[cnt]) {
+				t.Errorf("DiscoverySolicit.SerializeTo Opcode error Opcode=%x,data=%x,cnt=%x", d.Opcode, data[cnt:], cnt)
+			}
+			cnt++
+			if !reflect.DeepEqual(d.DiscoveryType, data[cnt]) {
+				t.Errorf("DiscoverySolicit.SerializeTo DiscoveryType error DiscoveryType=%X data=%x", d.DiscoveryType, data[cnt:cnt+1])
+			}
+			cnt++
+			if !reflect.DeepEqual(d.VendorType, data[cnt]) {
+				t.Errorf("DiscoverySolicit.SerializeTo VendorType error %x %x", data[cnt], d.VendorType)
+			}
+			cnt++
+
+			if !reflect.DeepEqual(d.Length, binary.BigEndian.Uint16(data[cnt:cnt+2])) {
+				t.Errorf("DiscoverySolicit.SerializeTo Length error Length=%x data[cnt:cnt+2]=%x", string(d.Length), string(binary.BigEndian.Uint16(data[cnt:cnt+2])))
+			}
+			cnt += 2
+
+			if !reflect.DeepEqual(d.VendorIDType, data[cnt]) {
+				t.Errorf("DiscoverySolicit.SerializeTo VendorIDType error VendorIDType=%x data=%x", d.VendorIDType, data[cnt])
+			}
+			cnt++
+			if !reflect.DeepEqual(d.VendorIDLength, binary.BigEndian.Uint16(data[cnt:cnt+2])) {
+				t.Errorf("DiscoverySolicit.SerializeTo VendorIDLength error VendorIDLength=%x data[cnt:cnt+2]=%x", d.VendorIDLength, data[cnt:cnt+2])
+			}
+			cnt += 2
+			digits = int(d.VendorIDLength)
+			if !reflect.DeepEqual(d.VendorID, data[cnt:cnt+digits]) {
+				t.Errorf("DiscoverySolicit.SerializeTo VendorID error %v %v", d.VendorID, data[cnt:cnt+3])
+			}
+			cnt += digits
+			if !reflect.DeepEqual(d.NWType, data[cnt]) {
+				t.Error("DiscoverySolicit.SerializeTo NWType error")
+			}
+			cnt++
+			if !reflect.DeepEqual(d.NWLength, binary.BigEndian.Uint16(data[cnt:cnt+2])) {
+				t.Error("DiscoverySolicit.SerializeTo NWLength error")
+			}
+			cnt += 2
+			//digits = int(d.NWLength)
+			for _, dvalue := range d.NWValue {
+				if !reflect.DeepEqual(dvalue, data[cnt]) {
+					t.Errorf("DiscoverySolicit.SerializeTo NWValue error %x %x", dvalue, data[cnt])
+				}
+				cnt++
+			}
+			// if !reflect.DeepEqual(string(d.NWValue), string(data[cnt:cnt+digits])) {
+			// 	t.Errorf("DiscoverySolicit.SerializeTo NWValue error %x %x", d.NWValue, data[cnt:cnt+digits])
+			// }
+			// cnt += 16
+			if !reflect.DeepEqual(d.DVType, data[cnt]) {
+				t.Error("DiscoverySolicit.SerializeTo DVType error")
+			}
+			cnt++
+			if !reflect.DeepEqual(d.DVLength, binary.BigEndian.Uint16(data[cnt:cnt+2])) {
+				t.Error("DiscoverySolicit.SerializeTo DVLength error")
+			}
+			cnt += 2
+			digits = int(d.DVLength)
+			if !reflect.DeepEqual(d.DVValue, data[cnt:cnt+digits]) {
+				t.Error("DiscoverySolicit.SerializeTo DVValue error")
+			}
+			cnt += digits
+			if !reflect.DeepEqual(d.SCPType, data[cnt]) {
+				t.Error("DiscoverySolicit.SerializeTo SCPType error")
+			}
+			cnt++
+			if !reflect.DeepEqual(d.SCPLength, binary.BigEndian.Uint16(data[cnt:cnt+2])) {
+				t.Error("DiscoverySolicit.SerializeTo SCPLength error")
+			}
+			cnt += 2
+			digits = int(d.SCPLength)
+			if !reflect.DeepEqual(d.SCPValue, data[cnt:cnt+digits]) {
+				t.Error("DiscoverySolicit.SerializeTo SCPValue error")
+			}
+			cnt += digits
+			if !reflect.DeepEqual(d.TunnelType, data[cnt]) {
+				t.Error("DiscoverySolicit.SerializeTo TunnelType error")
+			}
+			cnt++
+			if !reflect.DeepEqual(d.TunnelLength, binary.BigEndian.Uint16(data[cnt:cnt+2])) {
+				t.Error("DiscoverySolicit.SerializeTo TunnelLength error")
+			}
+			cnt += 2
+			digits = int(d.TunnelLength)
+			if !reflect.DeepEqual(d.TunnelValue, data[cnt:cnt+digits]) {
+				t.Error("DiscoverySolicit.SerializeTo TunnelValue error")
+			}
+			cnt += digits
+			if !reflect.DeepEqual(d.PadType, data[cnt]) {
+				t.Error("DiscoverySolicit.SerializeTo PadType error")
+			}
+			cnt++
+			if !reflect.DeepEqual(d.PadLength, binary.BigEndian.Uint16(data[cnt:cnt+2])) {
+				t.Error("DiscoverySolicit.SerializeTo PadLength error")
+			}
+			cnt += 2
+			digits = int(d.PadLength)
+			if !reflect.DeepEqual(d.PadValue, data[cnt:cnt+digits]) {
+				t.Errorf("DiscoverySolicit.SerializeTo PadValue error %x %x", d.PadValue, data[cnt:cnt+digits])
+			}
+		})
+	}
+}
+
+func TestDiscoveryHello_Decode(t *testing.T) {
+	type fields struct {
+		BaseLayer      layers.BaseLayer
+		Opcode         uint8
+		DiscoveryType  uint8
+		VendorType     uint8
+		Length         uint16
+		VendorIDType   uint8
+		VendorIDLength uint16
+		VendorID       []byte
+		NWType         uint8
+		NWLength       uint16
+		NWValue        []byte
+		DVType         uint8
+		DVLength       uint16
+		DVValue        []byte
+		SCPType        uint8
+		SCPLength      uint16
+		SCPValue       []byte
+		TunnelType     uint8
+		TunnelLength   uint16
+		TunnelValue    []byte
+		PadType        uint8
+		PadLength      uint16
+		PadValue       []byte
+	}
+	type args struct {
+		data []byte
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+	}{
+		// TODO: Add test cases.
+		{
+			name: "Decode-1",
+			args: args{
+				data: []byte{0xfd, 0x02, 0xfe, 0x00, 0x26, 0xfd, 0x00, 0x03, 0x2a, 0xea, 0x15, 0x06, 0x00, 0x10, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x07, 0x00, 0x01, 0x02, 0x08, 0x00, 0x01, 0x03, 0x0a, 0x00, 0x02, 0x00, 0x01, 0xff, 0x00, 0x01, 0x00},
+			},
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			d := &DiscoveryHello{
+				BaseLayer:      tt.fields.BaseLayer,
+				Opcode:         tt.fields.Opcode,
+				DiscoveryType:  tt.fields.DiscoveryType,
+				VendorType:     tt.fields.VendorType,
+				Length:         tt.fields.Length,
+				VendorIDType:   tt.fields.VendorIDType,
+				VendorIDLength: tt.fields.VendorIDLength,
+				VendorID:       tt.fields.VendorID,
+				NWType:         tt.fields.NWType,
+				NWLength:       tt.fields.NWLength,
+				NWValue:        tt.fields.NWValue,
+				DVType:         tt.fields.DVType,
+				DVLength:       tt.fields.DVLength,
+				DVValue:        tt.fields.DVValue,
+				SCPType:        tt.fields.SCPType,
+				SCPLength:      tt.fields.SCPLength,
+				SCPValue:       tt.fields.SCPValue,
+				TunnelType:     tt.fields.TunnelType,
+				TunnelLength:   tt.fields.TunnelLength,
+				TunnelValue:    tt.fields.TunnelValue,
+				PadType:        tt.fields.PadType,
+				PadLength:      tt.fields.PadLength,
+				PadValue:       tt.fields.PadValue,
+			}
+			if err := d.Decode(tt.args.data); (err != nil) != tt.wantErr {
+				t.Errorf("DiscoveryHello.Decode() error = %v, wantErr %v", err, tt.wantErr)
+			}
+
+			cnt := 0
+			digits := 0
+			if !reflect.DeepEqual(d.Opcode, tt.args.data[cnt]) {
+				t.Errorf("DiscoverySolicit.Decode Opcode error Opcode=%x,data=%x,cnt=%x", d.Opcode, tt.args.data[cnt:], cnt)
+			}
+			cnt++
+			if !reflect.DeepEqual(d.DiscoveryType, tt.args.data[cnt]) {
+				t.Errorf("DiscoverySolicit.Decode DiscoveryType error DiscoveryType=%X data=%x", d.DiscoveryType, tt.args.data[cnt:cnt+1])
+			}
+			cnt++
+			if !reflect.DeepEqual(d.VendorType, tt.args.data[cnt]) {
+				t.Errorf("DiscoverySolicit.Decode VendorType error %x %x", tt.args.data[cnt], d.VendorType)
+			}
+			cnt++
+
+			if !reflect.DeepEqual(d.Length, binary.BigEndian.Uint16(tt.args.data[cnt:cnt+2])) {
+				t.Errorf("DiscoverySolicit.Decode Length error Length=%x data[cnt:cnt+2]=%x", string(d.Length), string(binary.BigEndian.Uint16(tt.args.data[cnt:cnt+2])))
+			}
+			cnt += 2
+
+			if !reflect.DeepEqual(d.VendorIDType, tt.args.data[cnt]) {
+				t.Errorf("DiscoverySolicit.Decode VendorIDType error VendorIDType=%x data=%x", d.VendorIDType, tt.args.data[cnt])
+			}
+			cnt++
+			if !reflect.DeepEqual(d.VendorIDLength, binary.BigEndian.Uint16(tt.args.data[cnt:cnt+2])) {
+				t.Errorf("DiscoverySolicit.Decode VendorIDLength error VendorIDLength=%x data[cnt:cnt+2]=%x", d.VendorIDLength, tt.args.data[cnt:cnt+2])
+			}
+			cnt += 2
+			digits = int(d.VendorIDLength)
+			if !reflect.DeepEqual(d.VendorID, tt.args.data[cnt:cnt+digits]) {
+				t.Errorf("DiscoverySolicit.Decode VendorID error %v %v", d.VendorID, tt.args.data[cnt:cnt+3])
+			}
+			cnt += digits
+			if !reflect.DeepEqual(d.NWType, tt.args.data[cnt]) {
+				t.Error("DiscoverySolicit.Decode NWType error")
+			}
+			cnt++
+			if !reflect.DeepEqual(d.NWLength, binary.BigEndian.Uint16(tt.args.data[cnt:cnt+2])) {
+				t.Error("DiscoverySolicit.Decode NWLength error")
+			}
+			cnt += 2
+			//digits = int(d.NWLength)
+			for _, dvalue := range d.NWValue {
+				if !reflect.DeepEqual(dvalue, tt.args.data[cnt]) {
+					t.Errorf("DiscoverySolicit.Decode NWValue error %x %x", dvalue, tt.args.data[cnt])
+				}
+				cnt++
+			}
+			// if !reflect.DeepEqual(string(d.NWValue), string(tt.args.data[cnt:cnt+digits])) {
+			// 	t.Errorf("DiscoverySolicit.Decode NWValue error %x %x", d.NWValue, tt.args.data[cnt:cnt+digits])
+			// }
+			// cnt += 16
+			if !reflect.DeepEqual(d.DVType, tt.args.data[cnt]) {
+				t.Error("DiscoverySolicit.Decode DVType error")
+			}
+			cnt++
+			if !reflect.DeepEqual(d.DVLength, binary.BigEndian.Uint16(tt.args.data[cnt:cnt+2])) {
+				t.Error("DiscoverySolicit.Decode DVLength error")
+			}
+			cnt += 2
+			digits = int(d.DVLength)
+			if !reflect.DeepEqual(d.DVValue, tt.args.data[cnt:cnt+digits]) {
+				t.Error("DiscoverySolicit.Decode DVValue error")
+			}
+			cnt += digits
+			if !reflect.DeepEqual(d.SCPType, tt.args.data[cnt]) {
+				t.Error("DiscoverySolicit.Decode SCPType error")
+			}
+			cnt++
+			if !reflect.DeepEqual(d.SCPLength, binary.BigEndian.Uint16(tt.args.data[cnt:cnt+2])) {
+				t.Error("DiscoverySolicit.Decode SCPLength error")
+			}
+			cnt += 2
+			digits = int(d.SCPLength)
+			if !reflect.DeepEqual(d.SCPValue, tt.args.data[cnt:cnt+digits]) {
+				t.Error("DiscoverySolicit.Decode SCPValue error")
+			}
+			cnt += digits
+			if !reflect.DeepEqual(d.TunnelType, tt.args.data[cnt]) {
+				t.Error("DiscoverySolicit.Decode TunnelType error")
+			}
+			cnt++
+			if !reflect.DeepEqual(d.TunnelLength, binary.BigEndian.Uint16(tt.args.data[cnt:cnt+2])) {
+				t.Error("DiscoverySolicit.Decode TunnelLength error")
+			}
+			cnt += 2
+			digits = int(d.TunnelLength)
+			if !reflect.DeepEqual(d.TunnelValue, tt.args.data[cnt:cnt+digits]) {
+				t.Error("DiscoverySolicit.Decode TunnelValue error")
+			}
+			cnt += digits
+			if !reflect.DeepEqual(d.PadType, tt.args.data[cnt]) {
+				t.Error("DiscoverySolicit.Decode PadType error")
+			}
+			cnt++
+			if !reflect.DeepEqual(d.PadLength, binary.BigEndian.Uint16(tt.args.data[cnt:cnt+2])) {
+				t.Error("DiscoverySolicit.Decode PadLength error")
+			}
+			cnt += 2
+			digits = int(d.PadLength)
+			if !reflect.DeepEqual(d.PadValue, tt.args.data[cnt:cnt+digits]) {
+				t.Errorf("DiscoverySolicit.Decode PadValue error %x %x", d.PadValue, tt.args.data[cnt:cnt+digits])
+			}
+		})
+	}
+}
diff --git a/internal/pkg/core/l2oam/msg_generic_action_create.go b/internal/pkg/core/l2oam/msg_generic_action_create.go
new file mode 100644
index 0000000..a50c6a5
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_generic_action_create.go
@@ -0,0 +1,298 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"encoding/binary"
+	"encoding/hex"
+	"fmt"
+
+	"github.com/google/gopacket"
+	"github.com/google/gopacket/layers"
+)
+
+const (
+	ActionTypeProtocolFilter = 1
+
+	ActionTypeTrafficProfile = 2
+)
+
+// GenerateGenericActionCreate generates "Generic/Action Create" message
+func GenerateGenericActionCreate(actionType int) gopacket.SerializableLayer {
+	tibitData := &setGenericActionCreateReq{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OMI Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBiT OLT Management Interface
+		TOMIOpcode: 0x03,
+		// Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		// Object Context
+		OCBranch:   0x0c,
+		OCType:     0x0dce,
+		OCLength:   4,
+		OCInstance: 00000000,
+		//Vc
+		VcBranch: 0x6e,
+		VcLeaf:   0x7001,
+		VcLength: 4,
+		//OT
+		OT: []OTGenericActionCreate{{OTLength: 3, OTValue: getObjectType(actionType)}},
+		// End
+		EndBranch: 0,
+	}
+
+	return tibitData
+}
+
+func getObjectType(actionType int) []byte {
+	switch actionType {
+	case ActionTypeProtocolFilter:
+		return []byte{0x0c, 0x0c, 0xff}
+	case ActionTypeTrafficProfile:
+		return []byte{0x0c, 0x07, 0x0f}
+	default:
+		return []byte{0x00, 0x00, 0x00}
+	}
+}
+
+type setGenericActionCreateReq struct {
+	layers.BaseLayer
+	Opcode uint8
+	Flags      uint16
+	OAMPDUCode uint8
+	OUId       []byte // Organizationally Unique Identifier: 2a:ea:15 (Tibit Communications)
+	TOMIOpcode uint8
+	CTBranch   uint8
+	CTType     uint16
+	CTLength   uint8
+	CTInstance uint32
+	OCBranch   uint8
+	OCType     uint16
+	OCLength   uint8
+	OCInstance uint32
+	VcBranch uint8
+	VcLeaf   uint16
+	VcLength uint8
+	OT []OTGenericActionCreate
+	EndBranch uint8
+}
+
+// OTGenericActionCreate is a structure for "Object Type"
+type OTGenericActionCreate struct {
+	OTLength uint8
+	OTValue  []byte
+}
+
+// String returns the string expression of setGenericActionCreateReq
+func (d *setGenericActionCreateReq) String() string {
+	message := fmt.Sprintf("Opcode:%x, Flags:%x, OAMPDUCode:%x, OUId:%v", d.Opcode, d.Flags, d.OAMPDUCode, hex.EncodeToString(d.OUId))
+	message = fmt.Sprintf("%s, TOMIOpcode:%x", message, d.TOMIOpcode)
+	message = fmt.Sprintf("%s, CTBranch:%x, CTType:%x, CTLength:%x, CTInstance:%x", message, d.CTBranch, d.CTType, d.CTLength, d.CTInstance)
+	message = fmt.Sprintf("%s, OCBranch:%x, OCType:%x, OCLength:%x, OCInstance:%x", message, d.OCBranch, d.OCType, d.OCLength, d.OCInstance)
+	message = fmt.Sprintf("%s, VcBranch:%x, VcLeaf:%x, VcLength:%x", message, d.VcBranch, d.VcLeaf, d.VcLength)
+	for _, ot := range d.OT {
+		message = fmt.Sprintf("%s, OTLength:%x, OTValue:%v", message, ot.OTLength, hex.EncodeToString(ot.OTValue))
+	}
+	message = fmt.Sprintf("%s, EndBranch:%x", message, d.EndBranch)
+	return message
+}
+
+// Len returns the length of setGenericActionCreateReq
+func (d *setGenericActionCreateReq) Len() int {
+	return 21 + int(d.CTLength) + int(d.OCLength) + int(d.VcLength)
+
+}
+
+// LayerType returns the ethernet type of setGenericActionCreateReq
+func (d *setGenericActionCreateReq) LayerType() gopacket.LayerType { return layers.LayerTypeEthernet }
+
+// SerializeTo serializes a data structure to byte arrays
+func (d *setGenericActionCreateReq) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
+	plen := int(d.Len())
+	data, err := b.PrependBytes(plen)
+	if err != nil {
+		return err
+	}
+
+	i := 0
+	data[i] = byte(d.Opcode)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.Flags)
+	i += 2
+	data[i] = byte(d.OAMPDUCode)
+	i++
+	copy(data[i:i+len(d.OUId)], d.OUId)
+	i += len(d.OUId)
+	data[i] = byte(d.TOMIOpcode)
+	i++
+	data[i] = byte(d.CTBranch)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.CTType)
+	i += 2
+	data[i] = byte(d.CTLength)
+	i++
+	binary.BigEndian.PutUint32(data[i:i+4], d.CTInstance)
+	i += 4
+	data[i] = byte(d.OCBranch)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.OCType)
+	i += 2
+	data[i] = byte(d.OCLength)
+	i++
+	binary.BigEndian.PutUint32(data[i:i+4], d.OCInstance)
+	i += 4
+	data[i] = byte(d.VcBranch)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.VcLeaf)
+	i += 2
+	data[i] = byte(d.VcLength)
+	i++
+	for _, ot := range d.OT {
+		nextIndex := serializeObjectType(&ot, data, i)
+		i = nextIndex
+	}
+
+	data[i] = byte(d.EndBranch)
+
+	return nil
+
+}
+
+func serializeObjectType(ot *OTGenericActionCreate, data []byte, startIndex int) int {
+	i := startIndex
+	data[i] = ot.OTLength
+	i++
+	copy(data[i:i+int(ot.OTLength)], ot.OTValue)
+	i += int(ot.OTLength)
+
+	return i
+
+}
+
+// SetGenericActionCreateRes is a structure for a response of "Generic/Action Create"
+type SetGenericActionCreateRes struct {
+	layers.BaseLayer
+	Opcode uint8
+	Flags      uint16
+	OAMPDUCode uint8
+	OUId       []byte // Organizationally Unique Identifier: 2a:ea:15 (Tibit Communications)
+	TOMIOpcode uint8
+	CTBranch   uint8
+	CTType     uint16
+	CTLength   uint8
+	CTInstance uint32
+	OCBranch   uint8
+	OCType     uint16
+	OCLength   uint8
+	OCInstance uint32
+	VcBranch uint8
+	VcLeaf   uint16
+	VcLength uint8
+
+	ObOCLength   uint8
+	ObOCBranch   uint8
+	ObOCType     uint16
+	ObOCLength2  uint8
+	ObOCInstance []byte
+
+	EndBranch uint8
+}
+
+// ObOC is a structure for "Object OC"
+type ObOC struct {
+	ObOCLength   uint8
+	ObOCBranch   uint8
+	ObOCType     uint16
+	ObOCLength2  uint8
+	ObOCInstance []byte
+}
+
+// String returns the string expression of SetGenericActionCreateRes
+func (d *SetGenericActionCreateRes) String() string {
+	message := fmt.Sprintf("Opcode:%x, Flags:%x, OAMPDUCode:%x, OUId:%v", d.Opcode, d.Flags, d.OAMPDUCode, hex.EncodeToString(d.OUId))
+	message = fmt.Sprintf("%s, TOMIOpcode:%x", message, d.TOMIOpcode)
+	message = fmt.Sprintf("%s, CTBranch:%x, CTType:%x, CTLength:%x, CTInstance:%x", message, d.CTBranch, d.CTType, d.CTLength, d.CTInstance)
+	message = fmt.Sprintf("%s, OCBranch:%x, OCType:%x, OCLength:%x, OCInstance:%x", message, d.OCBranch, d.OCType, d.OCLength, d.OCInstance)
+	message = fmt.Sprintf("%s, VcBranch:%x, VcLeaf:%x, VcLength:%x", message, d.VcBranch, d.VcLeaf, d.VcLength)
+	message = fmt.Sprintf("%s, ObOCLength:%x, ObOCBranch:%x, ObOCType:%x, ObOCLength2:%x, ObOCInstance:%x, EndBranch:%x",
+		message, d.ObOCLength, d.ObOCBranch, d.ObOCType, d.ObOCLength2, d.ObOCInstance, d.EndBranch)
+	return message
+}
+
+// Decode decodes byte arrays to a data structure
+func (d *SetGenericActionCreateRes) Decode(data []byte) error {
+	i := 0
+	d.Opcode = data[i]
+	i++
+	d.Flags = binary.BigEndian.Uint16(data[i : i+2])
+	i += 2
+	d.OAMPDUCode = data[i]
+	i++
+	d.OUId = data[i : i+3]
+	i += len(d.OUId)
+	d.TOMIOpcode = data[i]
+	i++
+	d.CTBranch = data[i]
+	i++
+	d.CTType = binary.BigEndian.Uint16(data[i : i+2])
+	i += 2
+	d.CTLength = data[i]
+	i++
+	d.CTInstance = binary.BigEndian.Uint32(data[i : i+4])
+	i += 4
+	d.OCBranch = data[i]
+	i++
+	d.OCType = binary.BigEndian.Uint16(data[i : i+2])
+	i += 2
+	d.OCLength = data[i]
+	i++
+	d.OCInstance = binary.BigEndian.Uint32(data[i : i+4])
+	i += 4
+	d.VcBranch = data[i]
+	i++
+	d.VcLeaf = binary.BigEndian.Uint16(data[i : i+2])
+	i += 2
+	d.VcLength = data[i]
+	i++
+
+	d.ObOCLength = data[i]
+	i++
+	d.ObOCBranch = data[i]
+	i++
+	d.ObOCType = binary.BigEndian.Uint16(data[i : i+2])
+	i = i + 2
+	d.ObOCLength2 = data[i]
+	i++
+	d.ObOCInstance = data[i : i+int(d.ObOCLength2)]
+	i = i + int(d.ObOCLength2)
+
+	d.EndBranch = data[i]
+
+	return nil
+}
+
+// GetTrafficProfile returns the traffic profile of this message
+func (d *SetGenericActionCreateRes) GetTrafficProfile() []byte {
+	return d.ObOCInstance
+}
diff --git a/internal/pkg/core/l2oam/msg_generic_action_create_ds.go b/internal/pkg/core/l2oam/msg_generic_action_create_ds.go
new file mode 100644
index 0000000..40356d3
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_generic_action_create_ds.go
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GenerateGenericActionCreateDs generates "Generic/Action Create" message
+func GenerateGenericActionCreateDs() gopacket.SerializableLayer {
+
+	tibitData := &setGenericActionCreateReq{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OMI Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBiT OLT Management Interface
+		TOMIOpcode: 0x03,
+		// Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		// Object Context
+		OCBranch:   0x0c,
+		OCType:     0x0dce,
+		OCLength:   4,
+		OCInstance: 0x00000000,
+		//Vc
+		VcBranch: 0x6e,
+		VcLeaf:   0x7001,
+		VcLength: 4,
+		//OT
+		OT: []OTGenericActionCreate{{OTLength: 3, OTValue: []byte{0x0c, 0x02, 0x5d}}},
+		// End
+		EndBranch: 0,
+	}
+
+	return tibitData
+
+}
diff --git a/internal/pkg/core/l2oam/msg_generic_action_create_req.go b/internal/pkg/core/l2oam/msg_generic_action_create_req.go
new file mode 100644
index 0000000..766d1a1
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_generic_action_create_req.go
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+package l2oam
+
+import (
+	"encoding/binary"
+
+	"github.com/google/gopacket"
+)
+
+func GenerateGenericActionCreateReq() gopacket.SerializableLayer {
+
+	data := &TibitFrame{
+		Data: []byte{0x03, 0x00, 0x50, 0xfe, 0x2a, 0xea, 0x15, 0x03, 0x0c, 0x0c, 0x7a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0d, 0xce, 0x04, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x70, 0x01, 0x04, 0x03, 0x0c, 0x02, 0x5d, 0x00, 0x00},
+	}
+
+	binary.BigEndian.PutUint32(data.Data[12:16], getOltInstance())
+
+	return data
+
+}
diff --git a/internal/pkg/core/l2oam/msg_get_firmware_version.go b/internal/pkg/core/l2oam/msg_get_firmware_version.go
new file mode 100644
index 0000000..82995a7
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_get_firmware_version.go
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"encoding/hex"
+	"fmt"
+
+	"github.com/google/gopacket"
+)
+
+// GenerateGetFirmwareVersion generates "Running Firmware Version" message
+func GenerateGetFirmwareVersion() gopacket.SerializableLayer {
+	tibitData := &TOAMGetRequest{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OMI Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBiT OLT Management Interface
+		TOMIOpcode: 0x01,
+		// Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		// Object Context
+		OCBranch:   0x0c,
+		OCType:     0x0dce,
+		OCLength:   4,
+		OCInstance: 0x00000000,
+		// Vd
+		VdBranch: 0xde,
+		VdLeaf:   0x001b,
+		// End
+		EndBranch: 0,
+	}
+	return tibitData
+}
+
+// GetFirmwareVersionRes is a structure for a response of "Running Firmware Version"
+type GetFirmwareVersionRes struct {
+	ComResp   TOAMGetResponse
+	AKLength  uint8
+	AKValue   []byte
+	RVLength  uint8
+	RVValue   []byte
+	BSLength  uint8
+	BSValue   []byte
+	RNLength  uint8
+	RNValue   []byte
+	BDLength  uint8
+	BDValue   []byte
+	EndBranch uint8
+}
+
+// String returns the string expression of GetFirmwareVersionRes
+func (d *GetFirmwareVersionRes) String() string {
+	message := d.ComResp.String()
+	message = fmt.Sprintf("%s, AKLength:%02x, AKValue:%s, RVLength:%02x, RVValue:%s", message, d.AKLength, hex.EncodeToString(d.AKValue), d.RVLength, hex.EncodeToString(d.RVValue))
+	message = fmt.Sprintf("%s, BSLength:%02x, BSValue:%s, RNLength:%02x, RNValue:%s", message, d.BSLength, hex.EncodeToString(d.BSValue), d.RNLength, hex.EncodeToString(d.RNValue))
+	message = fmt.Sprintf("%s, BDLength:%02x, BDValue:%s, EndBranch:%02x", message, d.BDLength, hex.EncodeToString(d.BDValue), d.EndBranch)
+	return message
+}
+
+// Len returns the length of GetFirmwareVersionRes
+func (d *GetFirmwareVersionRes) Len() int {
+	return d.ComResp.Len() + int(d.ComResp.VcLength) + 1
+}
+
+// Decode decodes byte arrays to a data structure
+func (d *GetFirmwareVersionRes) Decode(data []byte) error {
+	d.ComResp.Decode(data)
+	i := d.ComResp.Len()
+	d.AKLength = data[i]
+	i++
+	d.AKValue = data[i : i+int(d.AKLength)]
+	i += int(d.AKLength)
+	d.RVLength = data[i]
+	i++
+	d.RVValue = data[i : i+int(d.RVLength)]
+	i += int(d.RVLength)
+	d.BSLength = data[i]
+	i++
+	d.BSValue = data[i : i+int(d.BSLength)]
+	i += int(d.BSLength)
+	d.RNLength = data[i]
+	i++
+	d.RNValue = data[i : i+int(d.RNLength)]
+	i += int(d.RNLength)
+	d.BDLength = data[i]
+	i++
+	d.BDValue = data[i : i+int(d.BDLength)]
+	i += int(d.BDLength)
+	d.EndBranch = data[i]
+
+	return nil
+}
+
+// GetFirmwareVersionNumber returns a firmware version number
+func (d *GetFirmwareVersionRes) GetFirmwareVersionNumber() string {
+	return string(d.RVValue)
+}
diff --git a/internal/pkg/core/l2oam/msg_get_mac_address.go b/internal/pkg/core/l2oam/msg_get_mac_address.go
new file mode 100644
index 0000000..e1df063
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_get_mac_address.go
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"encoding/hex"
+	"fmt"
+	"strings"
+
+	"github.com/google/gopacket"
+)
+
+// GenerateGetMacAddress generates "PON Port/MAC Address" message
+func GenerateGetMacAddress() gopacket.SerializableLayer {
+	tibitData := &TOAMGetRequest{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OAM Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBit OLT Management Interface
+		TOMIOpcode: 0x01,
+		// Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		// Object Context
+		OCBranch:   0x0c,
+		OCType:     0x0007,
+		OCLength:   4,
+		OCInstance: 0x00000000,
+		// Vd
+		VdBranch: 0x07,
+		VdLeaf:   0x0004,
+		// End
+		EndBranch: 0x00,
+	}
+	return tibitData
+}
+
+// GetMacAddressRes is a structure for a toam response
+type GetMacAddressRes struct {
+	ComResp TOAMGetResponse
+	EcLength  uint8
+	EcValue   []byte
+	EndBranch uint8
+}
+
+// String returns the string expression of GetMacAddressRes
+func (d *GetMacAddressRes) String() string {
+	message := d.ComResp.String()
+	message = fmt.Sprintf("%s, EcLength:%x, EcValue:%v, EndBranch:%x", message, d.EcLength, hex.EncodeToString(d.EcValue), d.EndBranch)
+	return message
+}
+
+// Len returns the length of GetMacAddressRes
+func (d *GetMacAddressRes) Len() int {
+	return d.ComResp.Len() + int(d.ComResp.VcLength) + 1
+}
+
+// Decode decodes byte arrays to a data structure
+func (d *GetMacAddressRes) Decode(data []byte) error {
+	d.ComResp.Decode(data)
+	i := d.ComResp.Len()
+	d.EcLength = data[i]
+	i++
+	d.EcValue = data[i : i+int(d.EcLength)]
+	i = i + int(d.EcLength)
+	d.EndBranch = data[i]
+
+	return nil
+}
+
+// GetMacAddress returns a MAC address
+func (d *GetMacAddressRes) GetMacAddress() string {
+	var buf []string
+	for _, b := range d.EcValue {
+		buf = append(buf, fmt.Sprintf("%02x", b))
+	}
+	return strings.Join(buf, ":")
+}
diff --git a/internal/pkg/core/l2oam/msg_get_manufacturer.go b/internal/pkg/core/l2oam/msg_get_manufacturer.go
new file mode 100644
index 0000000..74aa268
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_get_manufacturer.go
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"encoding/hex"
+	"fmt"
+
+	"github.com/google/gopacket"
+)
+
+// GenerateManuFacturerInfo generates "Device/Manufacturer Info" message
+func GenerateManuFacturerInfo() gopacket.SerializableLayer {
+
+	tibitData := &TOAMGetRequest{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		//OAMPrtocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		//TiBitT OLT Management
+		TOMIOpcode: 0x01,
+		//Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		//Object Context
+		OCBranch:   0x0c,
+		OCType:     0x0dce,
+		OCLength:   4,
+		OCInstance: 0x00000000,
+		//Vd
+		VdBranch: 0xde,
+		VdLeaf:   0x0006,
+		//End
+		EndBranch: 0x00,
+	}
+	return tibitData
+
+}
+
+// GetManufacturerRes is a structure for a toam response
+type GetManufacturerRes struct {
+	ComResp TOAMGetResponse
+	ECLength uint8
+	ECValue  []byte
+	EndBranch uint8
+}
+
+// String returns the string expression of GetManufacturerRes
+func (d *GetManufacturerRes) String() string {
+	message := d.ComResp.String()
+	message = fmt.Sprintf("%s, ECLength:%02x, ECValue:%v,EndBranch:%02x", message, d.ECLength, hex.EncodeToString(d.ECValue), d.EndBranch)
+	return message
+}
+
+// Len returns the length of GetManufacturerRes
+func (d *GetManufacturerRes) Len() int {
+	return d.ComResp.Len() + int(d.ComResp.VcLength) + 1
+}
+
+// Decode decodes byte arrays to a data structure
+func (d *GetManufacturerRes) Decode(data []byte) error {
+	d.ComResp.Decode(data)
+	i := d.ComResp.Len()
+	d.ECLength = data[i]
+	i++
+	d.ECValue = data[i : i+int(d.ECLength)]
+	i = i + int(d.ECLength)
+	d.EndBranch = data[i]
+
+	return nil
+}
+
+// GetManufacturer returns a manufacturer info.
+func (d *GetManufacturerRes) GetManufacturer() string {
+	return string(d.ECValue)
+}
diff --git a/internal/pkg/core/l2oam/msg_get_module_number.go b/internal/pkg/core/l2oam/msg_get_module_number.go
new file mode 100644
index 0000000..b256acd
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_get_module_number.go
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"encoding/hex"
+	"fmt"
+
+	"github.com/google/gopacket"
+)
+
+// GenerateGetModuleNumber generates "Device/Model Number" message
+func GenerateGetModuleNumber() gopacket.SerializableLayer {
+	tibitData := &TOAMGetRequest{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OMI Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBiT OLT Management Interface
+		TOMIOpcode: 0x81,
+		// Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		// Object Context
+		OCBranch:   0x0c,
+		OCType:     0x0dce,
+		OCLength:   4,
+		OCInstance: 0x00000000,
+		// Vd
+		VdBranch: 0xde,
+		VdLeaf:   0x000a,
+		// End
+		EndBranch: 0,
+	}
+	return tibitData
+}
+
+// GetModuleNumberRes is a structure for toam message
+type GetModuleNumberRes struct {
+	ComResp   TOAMGetResponse
+	EcLength  uint8
+	EcValue   []byte
+	EndBranch uint8
+}
+
+// String returns the string expression of GetModuleNumberRes
+func (d *GetModuleNumberRes) String() string {
+	message := d.ComResp.String()
+	message = fmt.Sprintf("%s, EcLength:%02x, EcValue:%s EndBranch:%02x", message, d.EcLength, hex.EncodeToString(d.EcValue), d.EndBranch)
+	return message
+}
+
+// Len returns the length of GetModuleNumberRes
+func (d *GetModuleNumberRes) Len() int {
+	return d.ComResp.Len() + int(d.ComResp.VcLength) + 1
+}
+
+// Decode decodes byte arrays to a data structure
+func (d *GetModuleNumberRes) Decode(data []byte) error {
+	d.ComResp.Decode(data)
+	i := d.ComResp.Len()
+	d.EcLength = data[i]
+	i++
+	d.EcValue = data[i : i+int(d.EcLength)]
+	i += int(d.EcLength)
+	d.EndBranch = data[i]
+
+	return nil
+}
+
+// GetModuleNumber returns a module number
+func (d *GetModuleNumberRes) GetModuleNumber() string {
+	return string(d.EcValue)
+}
diff --git a/internal/pkg/core/l2oam/msg_get_mpcp_llid.go b/internal/pkg/core/l2oam/msg_get_mpcp_llid.go
new file mode 100644
index 0000000..f1f7a10
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_get_mpcp_llid.go
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"encoding/binary"
+	"encoding/hex"
+	"fmt"
+
+	"github.com/google/gopacket"
+	"github.com/google/gopacket/layers"
+)
+
+// GetMpcpLLIdReq is a structure for "MPCP/LLID" message
+type GetMpcpLLIdReq struct {
+	layers.BaseLayer
+	Opcode uint8
+	Flags      uint16
+	OAMPDUCode uint8
+	OUId       []byte // Organizationally Unique Identifier: 2a:ea:15 (Tibit Communications)
+	TOMIOpcode uint8
+	OCBranch   uint8
+	OCType     uint16
+	OCLength   uint8
+	OCInstance uint32
+	VdBranch uint8
+	VdLeaf   uint16
+	EndBranch uint8
+}
+
+// GenerateGetMpcpLLId generates "MPCP/LLID" message
+func GenerateGetMpcpLLId(oc *TomiObjectContext) gopacket.SerializableLayer {
+	tibitData := &GetMpcpLLIdReq{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OMI Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBiT OLT Management Interface
+		TOMIOpcode: 0x01,
+		// Object Context
+		OCBranch:   oc.Branch,
+		OCType:     oc.Type,
+		OCLength:   oc.Length,
+		OCInstance: oc.Instance,
+		// Vd
+		VdBranch: 0xcc,
+		VdLeaf:   0x0007,
+		// End
+		EndBranch: 0,
+	}
+	return tibitData
+}
+
+// String returns the string expression of GetMpcpLLIdReq
+func (d *GetMpcpLLIdReq) String() string {
+	message := fmt.Sprintf("Opcode:%02x, Flags:%04x, OAMPDUCode:%02x, OUId:%v", d.Opcode, d.Flags, d.OAMPDUCode, hex.EncodeToString(d.OUId))
+	message = fmt.Sprintf("%s, TOMIOpcode:%02x", message, d.TOMIOpcode)
+	message = fmt.Sprintf("%s, OCBranch:%02x, OCType:%04x, OCLength:%02x, OCInstance:%08x", message, d.OCBranch, d.OCType, d.OCLength, d.OCInstance)
+	message = fmt.Sprintf("%s, VdBranch:%02x, VdLeaf:%04x, EndBranch:%02x", message, d.VdBranch, d.VdLeaf, d.EndBranch)
+	return message
+}
+
+// Len returns the length of GetMpcpLLIdReq
+func (d *GetMpcpLLIdReq) Len() int {
+	return 21
+}
+
+// LayerType returns the ethernet type of GetMpcpLLIdReq
+func (d *GetMpcpLLIdReq) LayerType() gopacket.LayerType { return layers.LayerTypeEthernet }
+
+// SerializeTo serializes a data structure to byte arrays
+func (d *GetMpcpLLIdReq) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
+	plen := int(d.Len())
+	data, err := b.PrependBytes(plen)
+	if err != nil {
+		return err
+	}
+
+	i := 0
+	data[i] = byte(d.Opcode)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.Flags)
+	i += 2
+	data[i] = byte(d.OAMPDUCode)
+	i++
+	copy(data[i:i+len(d.OUId)], d.OUId)
+	i += len(d.OUId)
+	data[i] = byte(d.TOMIOpcode)
+	i++
+	data[i] = byte(d.OCBranch)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.OCType)
+	i += 2
+	data[i] = byte(d.OCLength)
+	i++
+	binary.BigEndian.PutUint32(data[i:i+4], d.OCInstance)
+	i += 4
+	data[i] = byte(d.VdBranch)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.VdLeaf)
+	i += 2
+	data[i] = byte(d.EndBranch)
+
+	return nil
+}
+
+// GetMpcpLLIdRes is a structure for a response of "MPCP/LLID" message
+type GetMpcpLLIdRes struct {
+	layers.BaseLayer
+	Opcode uint8
+	Flags      uint16
+	OAMPDUCode uint8
+	OUId       []byte // Organizationally Unique Identifier: 2a:ea:15 (Tibit Communications)
+	TOMIOpcode uint8
+	OCBranch   uint8
+	OCType     uint16
+	OCLength   uint8
+	OCInstance uint32
+	VcBranch uint8
+	VcLeaf   uint16
+	VcLength uint8
+	EcLength uint8
+	EcValue  []byte
+	EndBranch uint8
+}
+
+// String returns the string expression of GetMpcpLLIdRes
+func (d *GetMpcpLLIdRes) String() string {
+	message := fmt.Sprintf("Opcode:%02x, Flags:%04x, OAMPDUCode:%02x, OUId:%v", d.Opcode, d.Flags, d.OAMPDUCode, hex.EncodeToString(d.OUId))
+	message = fmt.Sprintf("%s, TOMIOpcode:%02x", message, d.TOMIOpcode)
+	message = fmt.Sprintf("%s, OCBranch:%02x, OCType:%04x, OCLength:%02x, OCInstance:%08x", message, d.OCBranch, d.OCType, d.OCLength, d.OCInstance)
+	message = fmt.Sprintf("%s, VcBranch:%02x, VcLeaf:%04x, VcLength:%02x", message, d.VcBranch, d.VcLeaf, d.VcLength)
+	message = fmt.Sprintf("%s, EcLength:%02x, EcValue:%v, EndBranch:%02x", message, d.EcLength, hex.EncodeToString(d.EcValue), d.EndBranch)
+	return message
+}
+
+// Len returns the length of GetMpcpLLIdRes
+func (d *GetMpcpLLIdRes) Len() int {
+	return 20 + int(d.VcLength) + 1
+}
+
+// LayerType returns the ethernet type of GetMpcpLLIdRes
+func (d *GetMpcpLLIdRes) LayerType() gopacket.LayerType { return layers.LayerTypeEthernet }
+
+// Decode decodes byte arrays to a data structure
+func (d *GetMpcpLLIdRes) Decode(data []byte) error {
+	i := 0
+	d.Opcode = data[i]
+	i++
+	d.Flags = binary.BigEndian.Uint16(data[i : i+2])
+	i += 2
+	d.OAMPDUCode = data[i]
+	i++
+	d.OUId = data[i : i+3]
+	i += len(d.OUId)
+	d.TOMIOpcode = data[i]
+	i++
+	d.OCBranch = data[i]
+	i++
+	d.OCType = binary.BigEndian.Uint16(data[i : i+2])
+	i += 2
+	d.OCLength = data[i]
+	i++
+	d.OCInstance = binary.BigEndian.Uint32(data[i : i+4])
+	i += 4
+	d.VcBranch = data[i]
+	i++
+	d.VcLeaf = binary.BigEndian.Uint16(data[i : i+2])
+	i += 2
+	d.VcLength = data[i]
+	i++
+	d.EcLength = data[i]
+	i++
+	d.EcValue = data[i : i+int(d.EcLength)]
+	i += int(d.EcLength)
+	d.EndBranch = data[i]
+
+	return nil
+}
+
+// GetLLID returns a LLID
+func (d *GetMpcpLLIdRes) GetLLID() uint16 {
+	return binary.BigEndian.Uint16(d.EcValue)
+}
diff --git a/internal/pkg/core/l2oam/msg_get_mpcp_mac_address.go b/internal/pkg/core/l2oam/msg_get_mpcp_mac_address.go
new file mode 100644
index 0000000..7d9313c
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_get_mpcp_mac_address.go
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"encoding/binary"
+	"encoding/hex"
+	"fmt"
+	"strings"
+
+	"github.com/google/gopacket"
+	"github.com/google/gopacket/layers"
+)
+
+// GetMpcpMacAddressReq is a structure for "MPCP/MAC Address" message
+type GetMpcpMacAddressReq struct {
+	layers.BaseLayer
+	Opcode uint8
+	Flags      uint16
+	OAMPDUCode uint8
+	OUId       []byte // Organizationally Unique Identifier: 2a:ea:15 (Tibit Communications)
+	TOMIOpcode uint8
+	OCBranch   uint8
+	OCType     uint16
+	OCLength   uint8
+	OCInstance uint32
+	VdBranch uint8
+	VdLeaf   uint16
+	EndBranch uint8
+}
+
+// GenerateGetMpcpMacAddress generates "MPCP/MAC Address" message
+func GenerateGetMpcpMacAddress(oc *TomiObjectContext) gopacket.SerializableLayer {
+	tibitData := &GetMpcpMacAddressReq{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OMI Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBiT OLT Management Interface
+		TOMIOpcode: 0x01,
+		// Object Context
+		OCBranch:   oc.Branch,
+		OCType:     oc.Type,
+		OCLength:   oc.Length,
+		OCInstance: oc.Instance,
+		// Vd
+		VdBranch: 0xcc,
+		VdLeaf:   0x0008,
+		// End
+		EndBranch: 0,
+	}
+	return tibitData
+}
+
+// String returns the string expression of GetMpcpMacAddressReq
+func (d *GetMpcpMacAddressReq) String() string {
+	message := fmt.Sprintf("Opcode:%02x, Flags:%04x, OAMPDUCode:%02x, OUId:%v", d.Opcode, d.Flags, d.OAMPDUCode, hex.EncodeToString(d.OUId))
+	message = fmt.Sprintf("%s, TOMIOpcode:%02x", message, d.TOMIOpcode)
+	message = fmt.Sprintf("%s, OCBranch:%02x, OCType:%04x, OCLength:%02x, OCInstance:%08x", message, d.OCBranch, d.OCType, d.OCLength, d.OCInstance)
+	message = fmt.Sprintf("%s, VdBranch:%02x, VdLeaf:%04x, EndBranch:%02x", message, d.VdBranch, d.VdLeaf, d.EndBranch)
+	return message
+}
+
+// Len returns the length of GetModuleNumberRes
+func (d *GetMpcpMacAddressReq) Len() int {
+	return 21
+}
+
+// LayerType returns the ethernet type of GetMpcpMacAddressReq
+func (d *GetMpcpMacAddressReq) LayerType() gopacket.LayerType { return layers.LayerTypeEthernet }
+
+// SerializeTo serializes a data structure to byte arrays
+func (d *GetMpcpMacAddressReq) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
+	plen := int(d.Len())
+	data, err := b.PrependBytes(plen)
+	if err != nil {
+		return err
+	}
+
+	i := 0
+	data[i] = byte(d.Opcode)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.Flags)
+	i += 2
+	data[i] = byte(d.OAMPDUCode)
+	i++
+	copy(data[i:i+len(d.OUId)], d.OUId)
+	i += len(d.OUId)
+	data[i] = byte(d.TOMIOpcode)
+	i++
+	data[i] = byte(d.OCBranch)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.OCType)
+	i += 2
+	data[i] = byte(d.OCLength)
+	i++
+	binary.BigEndian.PutUint32(data[i:i+4], d.OCInstance)
+	i += 4
+	data[i] = byte(d.VdBranch)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.VdLeaf)
+	i += 2
+	data[i] = byte(d.EndBranch)
+
+	return nil
+}
+
+// GetMpcpMacAddressRes is a structure for a response of "MPCP/MAC Address" message
+type GetMpcpMacAddressRes struct {
+	layers.BaseLayer
+	Opcode uint8
+	Flags      uint16
+	OAMPDUCode uint8
+	OUId       []byte // Organizationally Unique Identifier: 2a:ea:15 (Tibit Communications)
+	TOMIOpcode uint8
+	OCBranch   uint8
+	OCType     uint16
+	OCLength   uint8
+	OCInstance uint32
+	VcBranch uint8
+	VcLeaf   uint16
+	VcLength uint8
+	EcLength uint8
+	EcValue  []byte
+	EndBranch uint8
+}
+
+// String returns the string expression of GetMpcpMacAddressRes
+func (d *GetMpcpMacAddressRes) String() string {
+	message := fmt.Sprintf("Opcode:%02x, Flags:%04x, OAMPDUCode:%02x, OUId:%v", d.Opcode, d.Flags, d.OAMPDUCode, hex.EncodeToString(d.OUId))
+	message = fmt.Sprintf("%s, TOMIOpcode:%02x", message, d.TOMIOpcode)
+	message = fmt.Sprintf("%s, OCBranch:%02x, OCType:%04x, OCLength:%02x, OCInstance:%08x", message, d.OCBranch, d.OCType, d.OCLength, d.OCInstance)
+	message = fmt.Sprintf("%s, VcBranch:%02x, VcLeaf:%04x, VcLength:%02x", message, d.VcBranch, d.VcLeaf, d.VcLength)
+	message = fmt.Sprintf("%s, EcLength:%02x, EcValue:%v, EndBranch:%02x", message, d.EcLength, hex.EncodeToString(d.EcValue), d.EndBranch)
+	return message
+}
+
+// Len returns the length of GetMpcpMacAddressRes
+func (d *GetMpcpMacAddressRes) Len() int {
+	return 20 + int(d.VcLength) + 1
+}
+
+// LayerType returns the ethernet type of GetMpcpMacAddressRes
+func (d *GetMpcpMacAddressRes) LayerType() gopacket.LayerType { return layers.LayerTypeEthernet }
+
+// Decode decodes byte arrays to a data structure
+func (d *GetMpcpMacAddressRes) Decode(data []byte) error {
+	i := 0
+	d.Opcode = data[i]
+	i++
+	d.Flags = binary.BigEndian.Uint16(data[i : i+2])
+	i += 2
+	d.OAMPDUCode = data[i]
+	i++
+	d.OUId = data[i : i+3]
+	i += len(d.OUId)
+	d.TOMIOpcode = data[i]
+	i++
+	d.OCBranch = data[i]
+	i++
+	d.OCType = binary.BigEndian.Uint16(data[i : i+2])
+	i += 2
+	d.OCLength = data[i]
+	i++
+	d.OCInstance = binary.BigEndian.Uint32(data[i : i+4])
+	i += 4
+	d.VcBranch = data[i]
+	i++
+	d.VcLeaf = binary.BigEndian.Uint16(data[i : i+2])
+	i += 2
+	d.VcLength = data[i]
+	i++
+	d.EcLength = data[i]
+	i++
+	d.EcValue = data[i : i+int(d.EcLength)]
+	i += int(d.EcLength)
+	d.EndBranch = data[i]
+
+	return nil
+}
+
+// GetMacAddress returns a MAC address
+func (d *GetMpcpMacAddressRes) GetMacAddress() string {
+	var buf []string
+	for _, b := range d.EcValue {
+		buf = append(buf, fmt.Sprintf("%02x", b))
+	}
+	return strings.Join(buf, ":")
+}
diff --git a/internal/pkg/core/l2oam/msg_get_pon_mode.go b/internal/pkg/core/l2oam/msg_get_pon_mode.go
new file mode 100644
index 0000000..74f8e00
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_get_pon_mode.go
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"encoding/hex"
+	"fmt"
+
+	"github.com/google/gopacket"
+)
+
+// GenerateGetPonMode generates "Device/PON Mode" message
+func GenerateGetPonMode() gopacket.SerializableLayer {
+	tibitData := &TOAMGetRequest{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OMI Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBiT OLT Management Interface
+		TOMIOpcode: 0x01,
+		// Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		// Object Context
+		OCBranch:   0x0c,
+		OCType:     0x0dce,
+		OCLength:   4,
+		OCInstance: 0x00000000,
+		// Vd
+		VdBranch: 0xde,
+		VdLeaf:   0x0002,
+		// End
+		EndBranch: 0,
+	}
+	return tibitData
+}
+
+// GetPonMode is a structure for toam message
+type GetPonMode struct {
+	ComResp   TOAMGetResponse
+	EcLength  uint8
+	EcValue   []byte
+	EndBranch uint8
+}
+
+// String returns the string expression of GetPonMode
+func (d *GetPonMode) String() string {
+	message := d.ComResp.String()
+	message = fmt.Sprintf("%s, EcLength:%02x, EcValue:%s EndBranch:%02x", message, d.EcLength, hex.EncodeToString(d.EcValue), d.EndBranch)
+	return message
+}
+
+// Len returns the length of GetPonMode
+func (d *GetPonMode) Len() int {
+	return d.ComResp.Len() + int(d.ComResp.VcLength) + 1
+}
+
+// Decode decodes byte arrays to a data structure
+func (d *GetPonMode) Decode(data []byte) error {
+	d.ComResp.Decode(data)
+	i := d.ComResp.Len()
+	d.EcLength = data[i]
+	i++
+	d.EcValue = data[i : i+int(d.EcLength)]
+	i += int(d.EcLength)
+	d.EndBranch = data[i]
+
+	return nil
+}
+
+// GetPonMode returns a PON mode
+func (d *GetPonMode) GetPonMode() string {
+	return string(d.EcValue)
+}
diff --git a/internal/pkg/core/l2oam/msg_get_serial_number.go b/internal/pkg/core/l2oam/msg_get_serial_number.go
new file mode 100644
index 0000000..73c662d
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_get_serial_number.go
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"encoding/hex"
+	"fmt"
+
+	"github.com/google/gopacket"
+)
+
+// GenerateGetSerialNumber generates "Device/Vendor Serial Number" message
+func GenerateGetSerialNumber() gopacket.SerializableLayer {
+	tibitData := &TOAMGetRequest{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OMI Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBiT OLT Management Interface
+		TOMIOpcode: 0x01,
+		// Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		// Object Context
+		OCBranch:   0x0c,
+		OCType:     0x0dce,
+		OCLength:   4,
+		OCInstance: 0x00000000,
+		// Vd
+		VdBranch: 0xde,
+		VdLeaf:   0x0012,
+		// End
+		EndBranch: 0,
+	}
+	return tibitData
+}
+
+// GetSerialNumberRes is a structure for toam message
+type GetSerialNumberRes struct {
+	ComResp   TOAMGetResponse
+	EcLength  uint8
+	EcValue   []byte
+	EndBranch uint8
+}
+
+// String returns the string expression of GetSerialNumberRes
+func (d *GetSerialNumberRes) String() string {
+	message := d.ComResp.String()
+	message = fmt.Sprintf("%s, EcLength:%02x, EcValue:%s EndBranch:%02x", message, d.EcLength, hex.EncodeToString(d.EcValue), d.EndBranch)
+	return message
+}
+
+// Len returns the length of GetSerialNumberRes
+func (d *GetSerialNumberRes) Len() int {
+	return d.ComResp.Len() + int(d.ComResp.VcLength) + 1
+}
+
+// Decode decodes byte arrays to a data structure
+func (d *GetSerialNumberRes) Decode(data []byte) error {
+	d.ComResp.Decode(data)
+	i := d.ComResp.Len()
+	d.EcLength = data[i]
+	i++
+	d.EcValue = data[i : i+int(d.EcLength)]
+	i += int(d.EcLength)
+	d.EndBranch = data[i]
+
+	return nil
+}
+
+// GetSerialNumber returns a serial number
+func (d *GetSerialNumberRes) GetSerialNumber() string {
+	return string(d.EcValue)
+}
diff --git a/internal/pkg/core/l2oam/msg_get_traffic_control_reference_table.go b/internal/pkg/core/l2oam/msg_get_traffic_control_reference_table.go
new file mode 100644
index 0000000..96b8c72
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_get_traffic_control_reference_table.go
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"encoding/binary"
+
+	"github.com/google/gopacket"
+	"github.com/google/gopacket/layers"
+)
+
+// GenerateGetTrafficControlReferenceTableReq generates "PON Link/Traffic Control Reference Table" message
+func GenerateGetTrafficControlReferenceTableReq(oc *TomiObjectContext) gopacket.SerializableLayer {
+	data := &TOAMGetRequest{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OAM Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBit OLT Management Interface
+		TOMIOpcode: 0x01,
+		// Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		// Object Context
+		OCBranch:   oc.Branch,
+		OCType:     oc.Type,
+		OCLength:   oc.Length,
+		OCInstance: oc.Instance,
+		// Vd
+		VdBranch: 0x01,
+		VdLeaf:   0x0007,
+		// End
+		EndBranch: 0x00,
+	}
+
+	return data
+}
+
+// GetTrafficControlReferenceTableRes is a structure for a response of "Traffic Control Reference Table" message
+type GetTrafficControlReferenceTableRes struct {
+	layers.BaseLayer
+	Opcode uint8
+	Flags      uint16
+	OAMPDUCode uint8
+	OUId       []byte // Organizationally Unique Identifier: 2a:ea:15 (Tibit Communications)
+	TOMIOpcode uint8
+	CTBranch   uint8
+	CTType     uint16
+	CTLength   uint8
+	CTInstance uint32
+	OCBranch   uint8
+	OCType     uint16
+	OCLength   uint8
+	OCInstance uint32
+	VcBranch uint8
+	VcLeaf   uint16
+	VcLength uint8
+
+	EcOcLengthDown   uint8
+	EcOcBranchDown   uint8
+	EcOcTypeDown     uint16
+	EcOcLength2Down  uint8
+	EcOcInstanceDown []byte
+
+	EcOcLengthUp   uint8
+	EcOcBranchUp   uint8
+	EcOcTypeUp     uint16
+	EcOcLength2Up  uint8
+	EcOcInstanceUp []byte
+
+	EndBranch uint8
+}
+
+// Decode decodes byte arrays to a data structure
+func (d *GetTrafficControlReferenceTableRes) Decode(data []byte) error {
+	i := 0
+	d.Opcode = data[i]
+	i++
+	d.Flags = binary.BigEndian.Uint16(data[i : i+2])
+	i += 2
+	d.OAMPDUCode = data[i]
+	i++
+	d.OUId = data[i : i+3]
+	i += len(d.OUId)
+	d.TOMIOpcode = data[i]
+	i++
+	d.CTBranch = data[i]
+	i++
+	d.CTType = binary.BigEndian.Uint16(data[i : i+2])
+	i += 2
+	d.CTLength = data[i]
+	i++
+	d.CTInstance = binary.BigEndian.Uint32(data[i : i+4])
+	i += 4
+	d.OCBranch = data[i]
+	i++
+	d.OCType = binary.BigEndian.Uint16(data[i : i+2])
+	i += 2
+	d.OCLength = data[i]
+	i++
+	d.OCInstance = binary.BigEndian.Uint32(data[i : i+4])
+	i += 4
+	d.VcBranch = data[i]
+	i++
+	d.VcLeaf = binary.BigEndian.Uint16(data[i : i+2])
+	i += 2
+	d.VcLength = data[i]
+	i++
+
+	d.EcOcLengthDown = data[i]
+	i++
+	d.EcOcBranchDown = data[i]
+	i++
+	d.EcOcTypeDown = binary.BigEndian.Uint16(data[i : i+2])
+	i += 2
+	d.EcOcLength2Down = data[i]
+	i++
+	d.EcOcInstanceDown = data[i : i+int(d.EcOcLength2Down)]
+	i += int(d.EcOcLength2Down)
+
+	d.EcOcLengthUp = data[i]
+	i++
+	d.EcOcBranchUp = data[i]
+	i++
+	d.EcOcTypeUp = binary.BigEndian.Uint16(data[i : i+2])
+	i += 2
+	d.EcOcLength2Up = data[i]
+	i++
+	d.EcOcInstanceUp = data[i : i+int(d.EcOcLength2Up)]
+	i += int(d.EcOcLength2Up)
+
+	d.EndBranch = data[i]
+
+	return nil
+}
+
+// GetReferenceControlDown returns a link id for downstream
+func (d *GetTrafficControlReferenceTableRes) GetReferenceControlDown() []byte {
+	return d.EcOcInstanceDown
+}
+
+// GetReferenceControlUp returns a link id for upstream
+func (d *GetTrafficControlReferenceTableRes) GetReferenceControlUp() []byte {
+	return d.EcOcInstanceUp
+}
diff --git a/internal/pkg/core/l2oam/msg_get_vendor_name.go b/internal/pkg/core/l2oam/msg_get_vendor_name.go
new file mode 100644
index 0000000..aa80fcd
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_get_vendor_name.go
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"encoding/hex"
+	"fmt"
+
+	"github.com/google/gopacket"
+)
+
+// GnerateGetVendorName generates "Device/Vendor Name"
+func GnerateGetVendorName() gopacket.SerializableLayer {
+	tibitData := &TOAMGetRequest{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OAM Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBit OLT Management Interface
+		TOMIOpcode: 0x01,
+		// Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		// Object Context
+		OCBranch:   0x0c,
+		OCType:     0x0dce,
+		OCLength:   4,
+		OCInstance: 0x00000000,
+		// Vd
+		VdBranch: 0xde,
+		VdLeaf:   0x0009,
+		// End
+		EndBranch: 0x00,
+	}
+
+	return tibitData
+}
+
+// GetVendorNameRes is a structure for a response of "Device/Vendor Name" message
+type GetVendorNameRes struct {
+	ComResp TOAMGetResponse
+	EcLength  uint8
+	EcValue   []byte
+	EndBranch uint8
+}
+
+// String returns the string expression of GetVendorNameRes
+func (d *GetVendorNameRes) String() string {
+	message := d.ComResp.String()
+	message = fmt.Sprintf("%s, EcLength:%v, EcValue:%v, EndBranch:%v", message, d.EcLength, hex.EncodeToString(d.EcValue), d.EndBranch)
+	return message
+}
+
+// Len returns the length of GetVendorNameRes
+func (d *GetVendorNameRes) Len() int {
+	return d.ComResp.Len() + int(d.ComResp.VcLength) + 1
+}
+
+// Decode decodes byte arrays to a data structure
+func (d *GetVendorNameRes) Decode(data []byte) error {
+	d.ComResp.Decode(data)
+	i := d.ComResp.Len()
+	d.EcLength = data[i]
+	i++
+	d.EcValue = data[i : i+int(d.EcLength)]
+	i = i + int(d.EcLength)
+	d.EndBranch = data[i]
+
+	return nil
+}
+
+// GetVendorName returns a vendor name
+func (d *GetVendorNameRes) GetVendorName() string {
+	return string(d.EcValue)
+}
diff --git a/internal/pkg/core/l2oam/msg_guaranteed_mbs.go b/internal/pkg/core/l2oam/msg_guaranteed_mbs.go
new file mode 100644
index 0000000..675e44e
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_guaranteed_mbs.go
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GenerateGuaranteedMbs generates "Traffic Profile/Guaranteed MBS" message
+func GenerateGuaranteedMbs() gopacket.SerializableLayer {
+
+	tibitData := &TOAMSetRequest{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OAM Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBit OLT Management Interface
+		TOMIOpcode: 0x03,
+		// Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		// Object Context
+		OCBranch:   0x0c,
+		OCType:     0x070f,
+		OCLength:   4,
+		OCInstance: 0x00000002,
+		// Vc
+		VcBranch: 0x7f,
+		VcLeaf:   0x0007,
+		VcLength: 5,
+		// EC
+		ECLength: 4,
+		ECValue:  []byte{0x00, 0x06, 0x40, 0x00},
+		// End
+		EndBranch: 0x00,
+	}
+	return tibitData
+}
diff --git a/internal/pkg/core/l2oam/msg_guaranteed_rate.go b/internal/pkg/core/l2oam/msg_guaranteed_rate.go
new file mode 100644
index 0000000..c26825d
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_guaranteed_rate.go
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"encoding/binary"
+
+	"github.com/google/gopacket"
+)
+
+// GenerateGuaranteedRate generates "Traffic Profile/Guaranteed Rate" message
+func GenerateGuaranteedRate(ecvalue []byte, trafficProfile []byte) gopacket.SerializableLayer {
+
+	tibitData := &TOAMSetRequest{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OAM Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBit OLT Management Interface
+		TOMIOpcode: 0x03,
+		// Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		// Object Context
+		OCBranch:   0x0c,
+		OCType:     0x070f,
+		OCLength:   4,
+		OCInstance: binary.BigEndian.Uint32(trafficProfile),
+		// Vc
+		VcBranch: 0x7f,
+		VcLeaf:   0x0006,
+		VcLength: uint8(1 + len(ecvalue)), //
+		// EC
+		ECLength: uint8(len(ecvalue)), //
+		ECValue:  ecvalue,             //0x80
+		// End
+		EndBranch: 0x00,
+	}
+	return tibitData
+}
diff --git a/internal/pkg/core/l2oam/msg_l2switching_domain_action_Inlet_entry_del.go b/internal/pkg/core/l2oam/msg_l2switching_domain_action_Inlet_entry_del.go
new file mode 100644
index 0000000..667fb7f
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_l2switching_domain_action_Inlet_entry_del.go
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GenerateL2switchingDomainActionInletEntryUsDel generates "L2 Switching Domain/Action Delete Inlet entry(for upstream)"
+func GenerateL2switchingDomainActionInletEntryUsDel(oc *TomiObjectContext,
+	tpid []byte, vid []byte, onuID *TomiObjectContext) gopacket.SerializableLayer {
+	tibitData := &L2switchingDomainRequest{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OAM Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBit OLT Management Interface
+		TOMIOpcode: 0x03,
+		// Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		// Object Context
+		OCBranch:   oc.Branch,
+		OCType:     oc.Type,
+		OCLength:   oc.Length,
+		OCInstance: oc.Instance,
+		// Vc
+		VcBranch: 0x5d,
+		VcLeaf:   0x7002,
+		VcLength: 21 + uint8(1+1+len(tpid)+1+len(vid)),
+		// Source OC
+		SOLength:    5,
+		SOBranch:    0x0c,
+		SOType:      0x0011,
+		SOValLength: 1,
+		SOInstance:  uint8(onuID.Instance),
+		// TagMatchList
+		TMLLength: 7,
+		TMLList: []TpidVid{
+			{
+				Length:     3,
+				TpIDLength: 0x80,
+				TpIDValue:  []byte{},
+				VIdLength:  1,
+				VIdValue:   []byte{0x00},
+			},
+			{
+				Length:     2,
+				TpIDLength: 0x80,
+				TpIDValue:  []byte{},
+				VIdLength:  0x80,
+				VIdValue:   []byte{},
+			},
+		},
+		// TagOpPop(UI)
+		TOPopLength: 1,
+		TOPopValue:  0x00,
+		// TagOpSetList
+		TOSLength: 3,
+		TOSList: []TpidVid{
+			{
+				Length:     2,
+				TpIDLength: 0x80,
+				TpIDValue:  []byte{},
+				VIdLength:  0x80,
+				VIdValue:   []byte{},
+			},
+		},
+		// TagOpPushList
+		TOPushLength: uint8(1 + 1 + len(tpid) + 1 + len(vid)),
+		TOPushList: []TpidVid{
+			{
+				Length:     uint8(1 + len(tpid) + 1 + len(vid)),
+				TpIDLength: uint8(len(tpid)),
+				TpIDValue:  tpid,
+				VIdLength:  uint8(len(vid)),
+				VIdValue:   vid,
+			},
+		},
+		// End
+		EndBranch: 0x00,
+	}
+
+	return tibitData
+}
+
+// GenerateL2switchingDomainActionInletEntryDsDel generates "L2 Switching Domain/Action Delete Inlet entry(for downstream)"
+func GenerateL2switchingDomainActionInletEntryDsDel(oc *TomiObjectContext, tpid []byte, vid []byte) gopacket.SerializableLayer {
+	tibitData := &L2switchingDomainRequest{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OAM Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBit OLT Management Interface
+		TOMIOpcode: 0x03,
+		// Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		// Object Context
+		OCBranch:   oc.Branch,
+		OCType:     oc.Type,
+		OCLength:   oc.Length,
+		OCInstance: oc.Instance,
+		// Vc
+		VcBranch: 0x5d,
+		VcLeaf:   0x7002,
+		VcLength: 16 + uint8(1+1+len(tpid)+1+len(vid)+4),
+		// Source OC
+		SOLength:    5,
+		SOBranch:    0x0c,
+		SOType:      0x0eca,
+		SOValLength: 1,
+		SOInstance:  0x00,
+		// TagMatchList
+		TMLLength: uint8(1 + 1 + len(tpid) + 1 + len(vid) + 3),
+		TMLList: []TpidVid{
+			{
+				Length:     uint8(1 + len(tpid) + 1 + len(vid)),
+				TpIDLength: uint8(len(tpid)),
+				TpIDValue:  tpid,
+				VIdLength:  uint8(len(vid)),
+				VIdValue:   vid,
+			},
+			{
+				Length:     2,
+				TpIDLength: 0x80,
+				TpIDValue:  []byte{},
+				VIdLength:  0x80,
+				VIdValue:   []byte{},
+			},
+		},
+		// TagOpPop(UI)
+		TOPopLength: 1,
+		TOPopValue:  0x01,
+		// TagOpSetList
+		TOSLength: 3,
+		TOSList: []TpidVid{
+			{
+				Length:     2,
+				TpIDLength: 0x80,
+				TpIDValue:  []byte{},
+				VIdLength:  0x80,
+				VIdValue:   []byte{},
+			},
+		},
+		// TagOpPushList
+		TOPushLength: 3,
+		TOPushList: []TpidVid{
+			{
+				Length:     2,
+				TpIDLength: 0x80,
+				TpIDValue:  []byte{},
+				VIdLength:  0x80,
+				VIdValue:   []byte{},
+			},
+		},
+		// End
+		EndBranch: 0x00,
+	}
+
+	return tibitData
+}
diff --git a/internal/pkg/core/l2oam/msg_l2switching_domain_action_lnlet_entry.go b/internal/pkg/core/l2oam/msg_l2switching_domain_action_lnlet_entry.go
new file mode 100644
index 0000000..b826292
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_l2switching_domain_action_lnlet_entry.go
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"encoding/binary"
+	"encoding/hex"
+	"fmt"
+
+	"github.com/google/gopacket"
+	"github.com/google/gopacket/layers"
+)
+
+// L2switchingDomainRequest is a structure for a request of "L2 Switching Domain/Action Inlet entry" message
+type L2switchingDomainRequest struct {
+	layers.BaseLayer
+	Opcode uint8
+	Flags      uint16
+	OAMPDUCode uint8
+	OUId       []byte // Organizationally Unique Identifier: 2a:ea:15 (Tibit Communications)
+	TOMIOpcode uint8
+	CTBranch   uint8
+	CTType     uint16
+	CTLength   uint8
+	CTInstance uint32
+	OCBranch   uint8
+	OCType     uint16
+	OCLength   uint8
+	OCInstance uint32
+	VcBranch uint8
+	VcLeaf   uint16
+	VcLength uint8
+	SOLength    uint8
+	SOBranch    uint8
+	SOType      uint16
+	SOValLength uint8
+	SOInstance  uint8
+	TMLLength uint8
+	TMLList   []TpidVid
+	TOPopLength uint8
+	TOPopValue  uint8
+	TOSLength uint8
+	TOSList   []TpidVid
+	TOPushLength uint8
+	TOPushList   []TpidVid
+	EndBranch  uint8
+	SizeMargin uint8
+}
+
+// TpidVid is a structure for TPID/VID set
+type TpidVid struct {
+	Length     uint8
+	TpIDLength uint8
+	TpIDValue  []byte
+	VIdLength  uint8
+	VIdValue   []byte
+}
+
+// String returns the string expression of L2switchingDomainRequest
+func (d *L2switchingDomainRequest) String() string {
+	message := fmt.Sprintf("Opcode:%x, Flags:%x, OAMPDUCode:%x, OUId:%v", d.Opcode, d.Flags, d.OAMPDUCode, hex.EncodeToString(d.OUId))
+	message = fmt.Sprintf("%s, TOMIOpcode:%x", message, d.TOMIOpcode)
+	message = fmt.Sprintf("%s, CTBranch:%x, CTType:%x, CTLength:%x, CTInstance:%x", message, d.CTBranch, d.CTType, d.CTLength, d.CTInstance)
+	message = fmt.Sprintf("%s, OCBranch:%x, OCType:%x, OCLength:%x, OCInstance:%x", message, d.OCBranch, d.OCType, d.OCLength, d.OCInstance)
+	message = fmt.Sprintf("%s, VcBranch:%x, VcLeaf:%x, VcLength:%x", message, d.VcBranch, d.VcLeaf, d.VcLength)
+	message = fmt.Sprintf("%s, SOLength:%x, SOBranch:%x, SOType:%x, SOValLength:%x, SOInstance:%x", message, d.SOLength, d.SOBranch, d.SOType, d.SOValLength, d.SOInstance)
+	message = fmt.Sprintf("%s, TMLLength:%x", message, d.TMLLength)
+	for i, tagMatch := range d.TMLList {
+		message = fmt.Sprintf("%s, %s", message, stringToTpidVid(&tagMatch, i))
+	}
+	message = fmt.Sprintf("%s, TOPopLength:%x, TOPopValue:%x", message, d.TOPopLength, d.TOPopValue)
+	message = fmt.Sprintf("%s, TOSLength:%x", message, d.TOSLength)
+	for i, tagOpSet := range d.TOSList {
+		message = fmt.Sprintf("%s, %s", message, stringToTpidVid(&tagOpSet, i))
+	}
+	message = fmt.Sprintf("%s, TOPushLength:%x", message, d.TOPushLength)
+	for i, tagOpPush := range d.TOPushList {
+		message = fmt.Sprintf("%s, %s", message, stringToTpidVid(&tagOpPush, i))
+	}
+	return message
+}
+
+func stringToTpidVid(tpidVid *TpidVid, index int) string {
+	message := fmt.Sprintf("EC[%v]:{Length:%x, TpIdLength:%x", index, tpidVid.Length, tpidVid.TpIDLength)
+	if tpidVid.TpIDLength != 128 {
+		message = fmt.Sprintf("%s, TpIdValue:%v", message, hex.EncodeToString(tpidVid.TpIDValue))
+	}
+	message = fmt.Sprintf("%s, VIdLength:%x", message, tpidVid.VIdLength)
+	if tpidVid.VIdLength != 128 {
+		message = fmt.Sprintf("%s, VIdValue:%v", message, hex.EncodeToString(tpidVid.VIdValue))
+	}
+	message = fmt.Sprintf("%s}", message)
+	return message
+}
+
+// Len returns the length of L2switchingDomainRequest
+func (d *L2switchingDomainRequest) Len() int {
+	return 22 + int(d.CTLength) + int(d.OCLength) + int(d.VcLength) + int(d.SizeMargin)
+}
+
+// LayerType returns the ethernet type of L2switchingDomainRequest
+func (d *L2switchingDomainRequest) LayerType() gopacket.LayerType { return layers.LayerTypeEthernet }
+
+// SerializeTo serializes a data structure to byte arrays
+func (d *L2switchingDomainRequest) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
+	plen := int(d.Len())
+	data, err := b.PrependBytes(plen)
+	if err != nil {
+		return err
+	}
+
+	i := 0
+	data[i] = byte(d.Opcode)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.Flags)
+	i += 2
+	data[i] = byte(d.OAMPDUCode)
+	i++
+	copy(data[i:i+len(d.OUId)], d.OUId)
+	i += len(d.OUId)
+	data[i] = byte(d.TOMIOpcode)
+	i++
+	data[i] = byte(d.CTBranch)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.CTType)
+	i += 2
+	data[i] = byte(d.CTLength)
+	i++
+	binary.BigEndian.PutUint32(data[i:i+4], d.CTInstance)
+	i += 4
+	data[i] = byte(d.OCBranch)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.OCType)
+	i += 2
+	data[i] = byte(d.OCLength)
+	i++
+	binary.BigEndian.PutUint32(data[i:i+4], d.OCInstance)
+	i += 4
+	data[i] = byte(d.VcBranch)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.VcLeaf)
+	i += 2
+	data[i] = byte(d.VcLength)
+	i++
+	data[i] = byte(d.SOLength)
+	i++
+	data[i] = byte(d.SOBranch)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.SOType)
+	i += 2
+	data[i] = byte(d.SOValLength)
+	i++
+	data[i] = byte(d.SOInstance)
+	i++
+	data[i] = byte(d.TMLLength)
+	i++
+	for _, tagMatch := range d.TMLList {
+		nextIndex := serializeTpidVid(&tagMatch, data, i)
+		i = nextIndex
+	}
+	data[i] = byte(d.TOPopLength)
+	i++
+	data[i] = byte(d.TOPopValue)
+	i++
+	data[i] = byte(d.TOSLength)
+	i++
+	for _, tagOpSet := range d.TOSList {
+		nextIndex := serializeTpidVid(&tagOpSet, data, i)
+		i = nextIndex
+	}
+	data[i] = d.TOPushLength
+	i++
+	for _, tagOpPush := range d.TOPushList {
+		nextIndex := serializeTpidVid(&tagOpPush, data, i)
+		i = nextIndex
+	}
+	data[i] = byte(d.EndBranch)
+
+	return nil
+}
+
+func serializeTpidVid(tpidVid *TpidVid, data []byte, startIndex int) int {
+	i := startIndex
+	data[i] = tpidVid.Length
+	i++
+	ln := tpidVid.TpIDLength
+	data[i] = ln
+	i++
+	if ln != 128 { // !Empty?
+		copy(data[i:i+int(ln)], tpidVid.TpIDValue)
+		i += int(ln)
+	}
+	ln = tpidVid.VIdLength
+	data[i] = ln
+	i++
+	if ln != 128 { // !Empty?
+		copy(data[i:i+int(ln)], tpidVid.VIdValue)
+		i += int(ln)
+	}
+	return i
+}
diff --git a/internal/pkg/core/l2oam/msg_l2switching_domain_action_lnlet_entry_ds.go b/internal/pkg/core/l2oam/msg_l2switching_domain_action_lnlet_entry_ds.go
new file mode 100644
index 0000000..6013ce3
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_l2switching_domain_action_lnlet_entry_ds.go
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GenerateL2switchingDomainActionLnletEntryDs generates "L2 Switching Domain/Action Add Inlet entry(for downstream)"
+func GenerateL2switchingDomainActionLnletEntryDs(oc *TomiObjectContext, tmTpidValue []byte, tmVidValue []byte) gopacket.SerializableLayer {
+
+	tibitData := &L2switchingDomainRequest{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OAM Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBit OLT Management Interface
+		TOMIOpcode: 0x03,
+		// Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		// Object Context
+		OCBranch:   oc.Branch,
+		OCType:     oc.Type,
+		OCLength:   oc.Length,
+		OCInstance: oc.Instance,
+		// Vc
+		VcBranch: 0x5d,
+		VcLeaf:   0x7001,
+		//VcLength: uint8(24 + len(tmTpidValue) + len(tmVidValue)), //27
+		VcLength: uint8(23 + len(tmTpidValue) + len(tmVidValue)), //26
+		// Source OC
+		SOLength:    5,
+		SOBranch:    0x0c,
+		SOType:      0x0eca,
+		SOValLength: 1,
+		SOInstance:  0x00,
+		// TagMatchList
+		//TMLLength: uint8(7 + len(tmTpidValue) + len(tmVidValue)), //10
+		TMLLength: uint8(6 + len(tmTpidValue) + len(tmVidValue)), //9
+		TMLList: []TpidVid{
+			{Length: uint8(2 + len(tmTpidValue) + len(tmVidValue)),
+				TpIDLength: uint8(len(tmTpidValue)),
+				TpIDValue:  tmTpidValue,
+				VIdLength:  uint8(len(tmVidValue)),
+				VIdValue:   tmVidValue},
+			////{Length: 5, TpIdLength: 2, TpIdValue: []byte{0x88, 0xa8}, VIdLength: 1, VIdValue: []byte{0x64}}
+
+			//{Length: 3, TpIdLength: 128, TpIdValue: []byte{0}, VIdLength: 1, VIdValue: []byte{0x00}}},
+			{Length: 2, TpIDLength: 128, TpIDValue: []byte{0}, VIdLength: 128, VIdValue: []byte{0x00}}},
+		// TagOpPop(UI)
+		TOPopLength: 1,
+		TOPopValue:  0x01,
+		// TagOpSetList
+		TOSLength: 3,
+		TOSList: []TpidVid{
+			{Length: 2, TpIDLength: 128, TpIDValue: []byte{0}, VIdLength: 128, VIdValue: []byte{0}}},
+		// TagOpPushList
+		TOPushLength: 3,
+		TOPushList: []TpidVid{
+			{Length: 2, TpIDLength: 128, TpIDValue: []byte{0}, VIdLength: 128, VIdValue: []byte{0}}},
+		// End
+		EndBranch: 0x00,
+	}
+
+	return tibitData
+}
diff --git a/internal/pkg/core/l2oam/msg_l2switching_domain_action_lnlet_entry_us.go b/internal/pkg/core/l2oam/msg_l2switching_domain_action_lnlet_entry_us.go
new file mode 100644
index 0000000..5f07c98
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_l2switching_domain_action_lnlet_entry_us.go
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GenerateL2switchingDomainActionLnletEntryUs generates "L2 Switching Domain/Action Add Inlet entry(upstream)" message
+func GenerateL2switchingDomainActionLnletEntryUs(oc *TomiObjectContext,
+	pushTpidValue []byte, pushVidValue []byte, onuID *TomiObjectContext) gopacket.SerializableLayer {
+
+	tibitData := &L2switchingDomainRequest{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OAM Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBit OLT Management Interface
+		TOMIOpcode: 0x03,
+		// Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		// Object Context
+		OCBranch:   oc.Branch,
+		OCType:     oc.Type,
+		OCLength:   oc.Length,
+		OCInstance: oc.Instance,
+		// Vc
+		VcBranch: 0x5d,
+		VcLeaf:   0x7001,
+		VcLength: uint8(24 + len(pushTpidValue) + len(pushVidValue)), //27
+		// Source OC
+		SOLength:    5,
+		SOBranch:    0x0c,
+		SOType:      0x0011,
+		SOValLength: 1,
+		SOInstance:  uint8(onuID.Instance),
+		// TagMatchList
+		TMLLength: 7,
+		TMLList: []TpidVid{
+			{
+				Length:     3,
+				TpIDLength: 0x80,
+				TpIDValue:  []byte{0},
+				VIdLength:  1,
+				VIdValue:   []byte{0x00},
+			},
+			{
+				Length:     2,
+				TpIDLength: 0x80,
+				TpIDValue:  []byte{0},
+				VIdLength:  0x80,
+				VIdValue:   []byte{0},
+			}},
+		// TagOpPop(UI)
+		TOPopLength: 1,
+		TOPopValue:  0x00,
+		// TagOpSetList
+		TOSLength: 3,
+		TOSList: []TpidVid{
+			{
+				Length:     2,
+				TpIDLength: 0x80,
+				TpIDValue:  []byte{0},
+				VIdLength:  0x80,
+				VIdValue:   []byte{0},
+			}},
+		// TagOpPushList
+		TOPushLength: uint8(3 + len(pushTpidValue) + len(pushVidValue)), //6
+		TOPushList: []TpidVid{
+			{Length: uint8(2 + len(pushTpidValue) + len(pushVidValue)),
+				TpIDLength: uint8(len(pushTpidValue)),
+				TpIDValue:  pushTpidValue,
+				VIdLength:  uint8(len(pushVidValue)),
+				VIdValue:   pushVidValue}}, ///{Length: 5, TpIdLength: 2, TpIdValue: []byte{0x88, 0xa8}, VIdLength: 1, VIdValue: []byte{0x64}}
+		// End
+		EndBranch: 0x00,
+	}
+
+	return tibitData
+}
diff --git a/internal/pkg/core/l2oam/msg_oampdu_information.go b/internal/pkg/core/l2oam/msg_oampdu_information.go
new file mode 100644
index 0000000..6d7a9f8
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_oampdu_information.go
@@ -0,0 +1,263 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"encoding/binary"
+	"encoding/hex"
+	"fmt"
+
+	"github.com/google/gopacket"
+	"github.com/google/gopacket/layers"
+)
+
+// OampduTlvTypeLocalInfo means that TLV type is "Local Information"
+var OampduTlvTypeLocalInfo uint8 = 0x01
+
+// OampduTlvTypeRemoteInfo means that TLV type is "Remote Information"
+var OampduTlvTypeRemoteInfo uint8 = 0x02
+
+// OampduTlvTypeOrganizationSpecificInfo means that TLV type is "Organization Specific Information"
+var OampduTlvTypeOrganizationSpecificInfo uint8 = 0xfe
+
+// GeneateKeepAlive1 generates "OAMPDU Information(first)"
+func GeneateKeepAlive1(isOnuPkgA bool) gopacket.SerializableLayer {
+	var osiLength uint8
+	var osiValue []byte
+	if isOnuPkgA {
+		osiLength = 7
+		osiValue = []byte{0x00, 0x10, 0x00, 0x00, 0x23}
+	} else {
+		osiLength = 8
+		osiValue = []byte{0x90, 0x82, 0x60, 0x02, 0x01, 0x01}
+	}
+	tibitData := &OAMPDUInformation{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OAM Protocol
+		Flags: 0x0008,
+		Code:  0x00,
+		// Local Information TLV
+		LIType:   OampduTlvTypeLocalInfo,
+		LILength: 16,
+		LIValue:  []byte{0x01, 0x00, 0x00, 0x00, 0x1b, 0x04, 0xb0, 0x2a, 0xea, 0x15, 0x00, 0x00, 0x00, 0x23},
+		// Organization Specific Information TLV
+		OSIType:   OampduTlvTypeOrganizationSpecificInfo,
+		OSILength: osiLength,
+		OSIValue:  osiValue,
+	}
+
+	return tibitData
+}
+
+// GeneateKeepAlive2 generates "OAMPDU Information(second)"
+func GeneateKeepAlive2(riValue []byte, isOnuPkgA bool) gopacket.SerializableLayer {
+	var osiLength uint8
+	var osiValue []byte
+	if isOnuPkgA {
+		osiLength = 7
+		osiValue = []byte{0x00, 0x10, 0x00, 0x00, 0x23}
+	} else {
+		osiLength = 8
+		osiValue = []byte{0x90, 0x82, 0x60, 0x02, 0x01, 0x01}
+	}
+	tibitData := &OAMPDUInformation{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OAM Protocol
+		Flags: 0x0030,
+		Code:  0x00,
+		// Local Information TLV
+		LIType:   OampduTlvTypeLocalInfo,
+		LILength: 16,
+		LIValue:  []byte{0x01, 0x00, 0x00, 0x00, 0x1b, 0x04, 0xb0, 0x2a, 0xea, 0x15, 0x00, 0x00, 0x00, 0x23},
+		// Remote Information TLV
+		RIType:   OampduTlvTypeRemoteInfo,
+		RILength: 16,
+		RIValue:  riValue,
+		// Organization Specific Information TLV
+		OSIType:   OampduTlvTypeOrganizationSpecificInfo,
+		OSILength: osiLength,
+		OSIValue:  osiValue,
+	}
+
+	return tibitData
+
+}
+
+// GeneateKeepAlive3 generates "OAMPDU Information(third)"
+func GeneateKeepAlive3(riValue []byte) gopacket.SerializableLayer {
+	tibitData := &OAMPDUInformation{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OAM Protocol
+		Flags: 0x0050,
+		Code:  0x00,
+		// Local Information TLV
+		LIType:   OampduTlvTypeLocalInfo,
+		LILength: 16,
+		LIValue:  []byte{0x01, 0x00, 0x00, 0x00, 0x1b, 0x04, 0xb0, 0x2a, 0xea, 0x15, 0x00, 0x00, 0x00, 0x23},
+		// Remote Information TLV
+		RIType:   OampduTlvTypeRemoteInfo,
+		RILength: 16,
+		RIValue:  riValue,
+	}
+
+	return tibitData
+
+}
+
+// OAMPDUInformation is a structure for "OAMPDU Information" message
+type OAMPDUInformation struct {
+	layers.BaseLayer
+	Opcode uint8
+	Flags uint16
+	Code  uint8
+	LIType   uint8
+	LILength uint8
+	LIValue  []byte
+	RIType   uint8
+	RILength uint8
+	RIValue  []byte
+	OSIType   uint8
+	OSILength uint8
+	OSIValue  []byte
+}
+
+// String returns the string expression of OAMPDUInformation
+func (d *OAMPDUInformation) String() string {
+	message := fmt.Sprintf("Opcode:%v, Flags:%v, Code:%v", d.Opcode, d.Flags, d.Code)
+	message = fmt.Sprintf("%s, LIType:%v, LILength:%v, LIValue:%v", message, d.LIType, d.LILength, hex.EncodeToString(d.LIValue))
+	message = fmt.Sprintf("%s, RIType:%v, RILength:%v, RIValue:%v", message, d.RIType, d.RILength, hex.EncodeToString(d.RIValue))
+	message = fmt.Sprintf("%s, OSIType:%v, OSILength:%v, OSIValue:%v", message, d.OSIType, d.OSILength, hex.EncodeToString(d.OSIValue))
+	return message
+}
+
+// Len returns the length of OAMPDUInformation
+func (d *OAMPDUInformation) Len() int {
+	len := (1) + (3) + int(d.LILength) + int(d.RILength) + int(d.OSILength)
+	return len
+}
+
+// LayerType returns the ethernet type of OAMPDUInformation
+func (d *OAMPDUInformation) LayerType() gopacket.LayerType { return layers.LayerTypeEthernet }
+
+// SerializeTo serializes a data structure to byte arrays
+func (d *OAMPDUInformation) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
+	plen := int(d.Len())
+	data, err := b.PrependBytes(plen)
+	if err != nil {
+		return err
+	}
+
+	i := 0
+	data[i] = byte(d.Opcode)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.Flags)
+	i = i + 2
+	data[i] = byte(d.Code)
+	i++
+
+	if d.LILength != 0 {
+		data[i] = byte(d.LIType)
+		data[i+1] = byte(d.LILength)
+		copy(data[i+2:i+int(d.LILength)], d.LIValue)
+		i = i + int(d.LILength)
+	}
+
+	if d.RILength != 0 {
+		data[i] = byte(d.RIType)
+		data[i+1] = byte(d.RILength)
+		copy(data[i+2:i+int(d.RILength)], d.RIValue)
+		i = i + int(d.RILength)
+	}
+
+	if d.OSILength != 0 {
+		data[i] = byte(d.OSIType)
+		data[i+1] = byte(d.OSILength)
+		copy(data[i+2:i+int(d.OSILength)], d.OSIValue)
+		//i = i + int(d.OSILength)
+	}
+
+	return nil
+}
+
+// Decode decodes byte arrays to a data structure
+func (d *OAMPDUInformation) Decode(data []byte) error {
+	i := 0
+	d.Opcode = data[i]
+	i++
+
+	d.Flags = binary.BigEndian.Uint16(data[i : i+2])
+	i = i + 2
+	d.Code = data[i]
+	i++
+
+	for {
+		if len(data) <= i {
+			break
+		}
+		tlvType := data[i]
+		tlvLength := data[i+1]
+		if tlvLength == 0 {
+			break
+		}
+		tlvValue := data[i+2 : i+int(tlvLength)]
+		i = i + int(tlvLength)
+
+		switch tlvType {
+		case OampduTlvTypeLocalInfo:
+			d.LIType = tlvType
+			d.LILength = tlvLength
+			d.LIValue = tlvValue
+		case OampduTlvTypeRemoteInfo:
+			d.RIType = tlvType
+			d.RILength = tlvLength
+			d.RIValue = tlvValue
+		case OampduTlvTypeOrganizationSpecificInfo:
+			d.OSIType = tlvType
+			d.OSILength = tlvLength
+			d.OSIValue = tlvValue
+		default:
+			return fmt.Errorf("tlvType Error: %v", tlvType)
+		}
+	}
+
+	return nil
+}
+
+// IsOnuPkgA returns true if message type of OAMPDUInformation is PkgA
+func (d *OAMPDUInformation) IsOnuPkgA() bool {
+	if d.OSILength == 0 {
+		// return true if OSILength is 0, this means the message is KeepAlive3
+		return true
+	} else if d.OSILength == 7 {
+		return (d.OSIValue[0] == 0x00 && d.OSIValue[1] == 0x10 && d.OSIValue[2] == 0x00)
+	}
+	return false
+}
+
+// IsOnuPkgB returns true if message type of OAMPDUInformation is PkgA
+func (d *OAMPDUInformation) IsOnuPkgB() bool {
+	if d.OSILength == 0 {
+		// return true if OSILength is 0, this means the message is KeepAlive3
+		return true
+	} else if d.OSILength == 7 {
+		return (d.OSIValue[0] == 0x90 && d.OSIValue[1] == 0x82 && d.OSIValue[2] == 0x60)
+	}
+	return false
+}
diff --git a/internal/pkg/core/l2oam/msg_pcscompu_tibitcom.go b/internal/pkg/core/l2oam/msg_pcscompu_tibitcom.go
new file mode 100644
index 0000000..80e7d18
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_pcscompu_tibitcom.go
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+package l2oam
+
+import (
+	"encoding/binary"
+	"encoding/hex"
+	"fmt"
+
+	"github.com/google/gopacket"
+)
+
+func GeneratePcscompuTivitcom(oc *TomiObjectContext) gopacket.SerializableLayer {
+	tibitData := &TOAMGetRequest{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OMI Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBiT OLT Management Interface
+		TOMIOpcode: 0x81,
+		// Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: 0x00000003,
+		// Object Context
+		OCBranch:   oc.Branch,
+		OCType:     oc.Type,
+		OCLength:   oc.Length,
+		OCInstance: oc.Instance,
+		// Vd
+		VdBranch: 0x01,
+		VdLeaf:   0x0007,
+		// End
+		EndBranch: 0,
+	}
+
+	return tibitData
+}
+
+type GetTrafficControlRefTableRes struct {
+	ComResp TOAMGetResponse
+
+	ECOC      []EcOcPONLinkTrafficControlReferenceTable
+	EndBranch uint8
+}
+
+type EcOcPONLinkTrafficControlReferenceTable struct {
+	EcOcLength   uint8
+	EcOcBranch   uint8
+	EcOcType     uint16
+	EcOcLength2  uint8
+	EcOcInstance []byte
+}
+
+func (d *GetTrafficControlRefTableRes) String() string {
+	message := d.ComResp.String()
+	for k, ec := range d.ECOC {
+		message = message + "EC[" + string(k) + "],EcOcLength:" + string(ec.EcOcLength) + ",EcOcBranch:" + string(ec.EcOcBranch) + ",EcOcType:" + string(ec.EcOcType) + ",EcOcLength2" + string(ec.EcOcLength2) + ",EcOcInstance:" + hex.EncodeToString(ec.EcOcInstance)
+	}
+	message = fmt.Sprintf("%s", message)
+	return message
+
+}
+
+func (d *GetTrafficControlRefTableRes) Decode(data []byte) error {
+	d.ComResp.Decode(data)
+	i := d.ComResp.Len()
+	for _, ec := range d.ECOC {
+		ec.EcOcLength = data[i]
+		i++
+		ec.EcOcBranch = data[i]
+		i++
+		binary.BigEndian.PutUint16(data[i:i+2], ec.EcOcType)
+		i = i + 2
+		ec.EcOcLength2 = data[i]
+		i++
+		copy(data[i:i+int(ec.EcOcLength2)], ec.EcOcInstance)
+		i = i + int(ec.EcOcLength2)
+	}
+
+	d.EndBranch = data[i]
+	i++
+
+	return nil
+
+}
diff --git a/internal/pkg/core/l2oam/msg_priority.go b/internal/pkg/core/l2oam/msg_priority.go
new file mode 100644
index 0000000..cbfff24
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_priority.go
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"encoding/binary"
+
+	"github.com/google/gopacket"
+)
+
+// GeneratePriority generates "Traffic Profile/Priority" message
+func GeneratePriority(trafficProfile []byte) gopacket.SerializableLayer {
+
+	tibitData := &TOAMSetRequest{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OAM Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBit OLT Management Interface
+		TOMIOpcode: 0x03,
+		// Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		// Object Context
+		OCBranch:   0x0c,
+		OCType:     0x070f,
+		OCLength:   4,
+		OCInstance: binary.BigEndian.Uint32(trafficProfile),
+		// Vc
+		VcBranch: 0x7f,
+		VcLeaf:   0x000a,
+		VcLength: 2,
+		// EC
+		ECLength: 1,
+		ECValue:  []byte{0x04},
+		// End
+		EndBranch: 0x00,
+	}
+	return tibitData
+}
diff --git a/internal/pkg/core/l2oam/msg_set_action_delete.go b/internal/pkg/core/l2oam/msg_set_action_delete.go
new file mode 100644
index 0000000..b05f661
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_set_action_delete.go
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"encoding/binary"
+
+	"github.com/google/gopacket"
+)
+
+// GenerateSetActionDelete generates "Generic/Action Delete" message
+func GenerateSetActionDelete(trafficProfile []byte, actionType int) gopacket.SerializableLayer {
+	ocInstance := binary.BigEndian.Uint32(trafficProfile)
+	objectType := getObjectType(actionType)
+	tibitData := &TOAMSetRequest{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OAM Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBit OLT Management Interface
+		TOMIOpcode: 0x03,
+		// Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		// Object Context
+		OCBranch:   objectType[0],
+		OCType:     binary.BigEndian.Uint16(objectType[1:3]),
+		OCLength:   4,
+		OCInstance: ocInstance,
+		// Vc
+		VcBranch: 0x6e,
+		VcLeaf:   0x7002,
+		VcLength: 0x80,
+		// EC
+		ECLength: 0,
+		ECValue:  []byte{},
+		// End
+		EndBranch: 0x00,
+	}
+	return tibitData
+}
+
+// GenerateSetActionDeleteStream generates "Generic/Action Delete(for stream)" message
+func GenerateSetActionDeleteStream(oc *TomiObjectContext) gopacket.SerializableLayer {
+	tibitData := &TOAMSetRequest{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OAM Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBit OLT Management Interface
+		TOMIOpcode: 0x03,
+		// Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		// Object Context
+		OCBranch:   oc.Branch,
+		OCType:     oc.Type,
+		OCLength:   oc.Length,
+		OCInstance: oc.Instance,
+		// Vc
+		VcBranch: 0x6e,
+		VcLeaf:   0x7002,
+		VcLength: 0x80,
+		// EC
+		ECLength: 0,
+		ECValue:  []byte{},
+		// End
+		EndBranch: 0x00,
+	}
+	return tibitData
+}
diff --git a/internal/pkg/core/l2oam/msg_set_action_delete_onu.go b/internal/pkg/core/l2oam/msg_set_action_delete_onu.go
new file mode 100644
index 0000000..fe8a728
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_set_action_delete_onu.go
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GenerateSetActionDeleteOnu generates "Generic/Action Delete" message
+func GenerateSetActionDeleteOnu(oc *TomiObjectContext) gopacket.SerializableLayer {
+	tibitData := &TOAMSetRequest{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OAM Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBit OLT Management Interface
+		TOMIOpcode: 0x03,
+		// Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		// Object Context
+		OCBranch:   oc.Branch,
+		OCType:     oc.Type,
+		OCLength:   oc.Length,
+		OCInstance: oc.Instance,
+		// Vc
+		VcBranch: 0x6e,
+		VcLeaf:   0x7002,
+		VcLength: 0x80,
+		// EC
+		ECLength: 0,
+		ECValue:  []byte{},
+		// End
+		EndBranch: 0x00,
+	}
+	return tibitData
+}
diff --git a/internal/pkg/core/l2oam/msg_set_action_reset.go b/internal/pkg/core/l2oam/msg_set_action_reset.go
new file mode 100644
index 0000000..0dc4a28
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_set_action_reset.go
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"encoding/binary"
+
+	"github.com/google/gopacket"
+)
+
+// GenerateSetActionReset generates "Device/Action Reset" message
+func GenerateSetActionReset() gopacket.SerializableLayer {
+
+	data := &TibitFrame{
+		Data: []byte{
+			0x03, 0x00, 0x50, 0xfe, 0x2a, 0xea, 0x15, 0x03,
+			0x0c, 0x0c, 0x7a, 0x04, 0x00, 0x00, 0x00, 0x00,
+			0x0c, 0x0d, 0xce, 0x04, 0x00, 0x00, 0x00, 0x00,
+			0xde, 0x70, 0x01, 0x80, 0x00, 0x00},
+	}
+
+	binary.BigEndian.PutUint32(data.Data[12:16], getOltInstance())
+
+	return data
+
+}
diff --git a/internal/pkg/core/l2oam/msg_set_admin_state.go b/internal/pkg/core/l2oam/msg_set_admin_state.go
new file mode 100644
index 0000000..aae58ab
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_set_admin_state.go
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GenerateSetAdminState generates "PON Port/Admin State" message
+func GenerateSetAdminState() gopacket.SerializableLayer {
+	tibitData := &TOAMSetRequest{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OAM Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBit OLT Management Interface
+		TOMIOpcode: 0x03,
+		// Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		// Object Context
+		OCBranch:   0x0c,
+		OCType:     0x0007,
+		OCLength:   4,
+		OCInstance: 0x00000000,
+		// Vc
+		VcBranch: 0x07,
+		VcLeaf:   0x0001,
+		VcLength: 2,
+		// EC
+		ECLength: 1,
+		ECValue:  []byte{0x01},
+		// End
+		EndBranch: 0x00,
+	}
+	return tibitData
+
+}
+
+// GenerateSetAdminStateDelete generates "PON Port/Admin State(for delete)" message
+func GenerateSetAdminStateDelete() gopacket.SerializableLayer {
+	tibitData := &TOAMSetRequest{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OAM Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBit OLT Management Interface
+		TOMIOpcode: 0x03,
+		// Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		// Object Context
+		OCBranch:   0x0c,
+		OCType:     0x0007,
+		OCLength:   4,
+		OCInstance: 0x00000000,
+		// Vc
+		VcBranch: 0x07,
+		VcLeaf:   0x0001,
+		VcLength: 2,
+		// EC
+		ECLength: 1,
+		ECValue:  []byte{0x02},
+		// End
+		EndBranch: 0x00,
+	}
+	return tibitData
+
+}
diff --git a/internal/pkg/core/l2oam/msg_set_capture_protocols.go b/internal/pkg/core/l2oam/msg_set_capture_protocols.go
new file mode 100644
index 0000000..49c335a
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_set_capture_protocols.go
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"encoding/binary"
+
+	"github.com/google/gopacket"
+	"github.com/google/gopacket/layers"
+)
+
+// GenerateCaptureProtocols generates "Protocol Filter/Capture Protocols" message
+func GenerateCaptureProtocols(ocInstance uint32) gopacket.SerializableLayer {
+
+	return &SetGenerteCaptureProtocolsreq{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OAM Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBit OLT Management Interface
+		TOMIOpcode: 0x03,
+		// Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		// Object Context
+		OCBranch:   0x0c,
+		OCType:     0x0cff,
+		OCLength:   4,
+		OCInstance: ocInstance,
+		// Vc
+		VcBranch: 0xcf,
+		VcLeaf:   0x0003,
+		VcLength: 5,
+		// EC
+		ECLength: 4,
+		//Protocol
+		ProtocolLength: 1,
+		ProtocolValue:  0x01,
+		//Action
+		ActionLength: 1,
+		ActionValue:  0x01,
+		// End
+		EndBranch: 0x00,
+	}
+
+}
+
+// SetGenerteCaptureProtocolsreq is a structure for a request of "Protocol Filter/Capture Protocols" message
+type SetGenerteCaptureProtocolsreq struct {
+	layers.BaseLayer
+	Opcode uint8
+	Flags      uint16
+	OAMPDUCode uint8
+	OUId       []byte // Organizationally Unique Identifier: 2a:ea:15 (Tibit Communications)
+	TOMIOpcode uint8
+	CTBranch   uint8
+	CTType     uint16
+	CTLength   uint8
+	CTInstance uint32
+	OCBranch   uint8
+	OCType     uint16
+	OCLength   uint8
+	OCInstance uint32
+	VcBranch uint8
+	VcLeaf   uint16
+	VcLength uint8
+	ECLength uint8
+	ProtocolLength uint8
+	ProtocolValue  uint8
+	ActionLength uint8
+	ActionValue  uint8
+	EndBranch uint8
+}
+
+// Len returns the length of SetGenerteCaptureProtocolsreq
+func (d *SetGenerteCaptureProtocolsreq) Len() int {
+	return 21 + int(d.CTLength) + int(d.OCLength) + int(d.VcLength)
+}
+
+// LayerType returns the ethernet type of SetGenerteCaptureProtocolsreq
+func (d *SetGenerteCaptureProtocolsreq) LayerType() gopacket.LayerType {
+	return layers.LayerTypeEthernet
+}
+
+// SerializeTo serializes a data structure to byte arrays
+func (d *SetGenerteCaptureProtocolsreq) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
+	plen := int(d.Len())
+	data, err := b.PrependBytes(plen)
+	if err != nil {
+		return err
+	}
+
+	i := 0
+	data[i] = byte(d.Opcode)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.Flags)
+	i += 2
+	data[i] = byte(d.OAMPDUCode)
+	i++
+	copy(data[i:i+len(d.OUId)], d.OUId)
+	i += len(d.OUId)
+	data[i] = byte(d.TOMIOpcode)
+	i++
+	data[i] = byte(d.CTBranch)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.CTType)
+	i += 2
+	data[i] = byte(d.CTLength)
+	i++
+	binary.BigEndian.PutUint32(data[i:i+4], d.CTInstance)
+	i += 4
+	data[i] = byte(d.OCBranch)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.OCType)
+	i += 2
+	data[i] = byte(d.OCLength)
+	i++
+	binary.BigEndian.PutUint32(data[i:i+4], d.OCInstance)
+	i += 4
+	data[i] = byte(d.VcBranch)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.VcLeaf)
+	i += 2
+	data[i] = byte(d.VcLength)
+	i++
+	data[i] = byte(d.ECLength)
+	i++
+	data[i] = byte(d.ProtocolLength)
+	i++
+	data[i] = byte(d.ProtocolValue)
+	i++
+	data[i] = byte(d.ActionLength)
+	i++
+	data[i] = byte(d.ActionValue)
+	i++
+	data[i] = byte(d.EndBranch)
+
+	return nil
+
+}
+
+// Decode decodes byte arrays to a data structure
+func (d *SetGenerteCaptureProtocolsreq) Decode(data []byte) error {
+	i := 0
+	d.Opcode = data[i]
+	i++
+	d.Flags = binary.BigEndian.Uint16(data[i : i+2])
+	i += 2
+	d.OAMPDUCode = data[i]
+	i++
+	d.OUId = data[i : i+3]
+	i += len(d.OUId)
+	d.TOMIOpcode = data[i]
+	i++
+	d.CTBranch = data[i]
+	i++
+	d.CTType = binary.BigEndian.Uint16(data[i : i+2])
+	i += 2
+	d.CTLength = data[i]
+	i++
+	d.CTInstance = binary.BigEndian.Uint32(data[i : i+4])
+	i += 4
+	d.OCBranch = data[i]
+	i++
+	d.OCType = binary.BigEndian.Uint16(data[i : i+2])
+	i += 2
+	d.OCLength = data[i]
+	i++
+	d.OCInstance = binary.BigEndian.Uint32(data[i : i+4])
+	i += 4
+	d.VcBranch = data[i]
+	i++
+	d.VcLeaf = binary.BigEndian.Uint16(data[i : i+2])
+	i += 2
+	d.VcLength = data[i]
+	i++
+	d.ECLength = data[i]
+	i++
+	d.ProtocolLength = data[i]
+	i++
+	d.ProtocolValue = data[i]
+	i++
+	d.ActionLength = data[i]
+	i++
+	d.ActionValue = data[i]
+	i++
+	d.EndBranch = data[i]
+
+	return nil
+}
diff --git a/internal/pkg/core/l2oam/msg_set_default_outlet.go b/internal/pkg/core/l2oam/msg_set_default_outlet.go
new file mode 100644
index 0000000..a794903
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_set_default_outlet.go
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"encoding/binary"
+	"encoding/hex"
+	"fmt"
+
+	"github.com/google/gopacket"
+	"github.com/google/gopacket/layers"
+)
+
+// GenerateSetDefaultOutlet generates "Default Outlet" message
+func GenerateSetDefaultOutlet(oc *TomiObjectContext, onuID *TomiObjectContext) gopacket.SerializableLayer {
+
+	tibitData := &DefaultOutletRequest{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OAM Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBit OLT Management Interface
+		TOMIOpcode: 0x03,
+		// Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		// Object Context
+		OCBranch:   oc.Branch,
+		OCType:     oc.Type,
+		OCLength:   oc.Length,
+		OCInstance: oc.Instance,
+		// Vc
+		VcBranch: 0x5d,
+		VcLeaf:   0x0003,
+		VcLength: 0x09,
+		// Default Outlet
+		DOLength:    8,
+		DOBranch:    0x0c,
+		DOType:      0x0011,
+		DOValLength: 4,
+		DOInstance:  onuID.Instance,
+		// End
+		EndBranch: 0x00,
+	}
+
+	return tibitData
+}
+
+// DefaultOutletRequest is a structure for a request of "Default Outlet" message
+type DefaultOutletRequest struct {
+	layers.BaseLayer
+	Opcode uint8
+	Flags      uint16
+	OAMPDUCode uint8
+	OUId       []byte // Organizationally Unique Identifier: 2a:ea:15 (Tibit Communications)
+	TOMIOpcode uint8
+	CTBranch   uint8
+	CTType     uint16
+	CTLength   uint8
+	CTInstance uint32
+	OCBranch   uint8
+	OCType     uint16
+	OCLength   uint8
+	OCInstance uint32
+	VcBranch uint8
+	VcLeaf   uint16
+	VcLength uint8
+	DOLength    uint8
+	DOBranch    uint8
+	DOType      uint16
+	DOValLength uint8
+	DOInstance  uint32
+	EndBranch uint8
+}
+
+// String returns the string expression of DefaultOutletRequest
+func (d *DefaultOutletRequest) String() string {
+	message := fmt.Sprintf("Opcode:%x, Flags:%x, OAMPDUCode:%x, OUId:%v", d.Opcode, d.Flags, d.OAMPDUCode, hex.EncodeToString(d.OUId))
+	message = fmt.Sprintf("%s, TOMIOpcode:%x", message, d.TOMIOpcode)
+	message = fmt.Sprintf("%s, CTBranch:%x, CTType:%x, CTLength:%x, CTInstance:%x", message, d.CTBranch, d.CTType, d.CTLength, d.CTInstance)
+	message = fmt.Sprintf("%s, OCBranch:%x, OCType:%x, OCLength:%x, OCInstance:%x", message, d.OCBranch, d.OCType, d.OCLength, d.OCInstance)
+	message = fmt.Sprintf("%s, VcBranch:%x, VcLeaf:%x, VcLength:%x", message, d.VcBranch, d.VcLeaf, d.VcLength)
+	message = fmt.Sprintf("%s, DOLength:%x, DOBranch:%x, DOType:%x, DOValLength:%x, DOInstance:%x", message, d.DOLength, d.DOBranch, d.DOType, d.DOValLength, d.DOInstance)
+
+	return message
+}
+
+// Len returns the length of DefaultOutletRequest
+func (d *DefaultOutletRequest) Len() int {
+	return 38
+}
+
+// LayerType returns the ethernet type of DefaultOutletRequest
+func (d *DefaultOutletRequest) LayerType() gopacket.LayerType { return layers.LayerTypeEthernet }
+
+// SerializeTo serializes a data structure to byte arrays
+func (d *DefaultOutletRequest) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
+	plen := int(d.Len())
+	data, err := b.PrependBytes(plen)
+	if err != nil {
+		return err
+	}
+
+	i := 0
+	data[i] = byte(d.Opcode)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.Flags)
+	i += 2
+	data[i] = byte(d.OAMPDUCode)
+	i++
+	copy(data[i:i+len(d.OUId)], d.OUId)
+	i += len(d.OUId)
+	data[i] = byte(d.TOMIOpcode)
+	i++
+	data[i] = byte(d.CTBranch)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.CTType)
+	i += 2
+	data[i] = byte(d.CTLength)
+	i++
+	binary.BigEndian.PutUint32(data[i:i+4], d.CTInstance)
+	i += 4
+	data[i] = byte(d.OCBranch)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.OCType)
+	i += 2
+	data[i] = byte(d.OCLength)
+	i++
+	binary.BigEndian.PutUint32(data[i:i+4], d.OCInstance)
+	i += 4
+	data[i] = byte(d.VcBranch)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.VcLeaf)
+	i += 2
+	data[i] = byte(d.VcLength)
+	i++
+	data[i] = byte(d.DOLength)
+	i++
+	data[i] = byte(d.DOBranch)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.DOType)
+	i += 2
+	data[i] = byte(d.DOValLength)
+	i++
+	binary.BigEndian.PutUint32(data[i:i+4], d.DOInstance)
+	i += 4
+	data[i] = byte(d.EndBranch)
+
+	return nil
+}
diff --git a/internal/pkg/core/l2oam/msg_set_hbtx_period.go b/internal/pkg/core/l2oam/msg_set_hbtx_period.go
new file mode 100644
index 0000000..f2b784a
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_set_hbtx_period.go
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GenerateSetHbtxPeriod generates "OAM/HBTx Period"
+func GenerateSetHbtxPeriod() gopacket.SerializableLayer {
+
+	tibitData := &TOAMSetRequest{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OAM Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBit OLT Management Interface
+		TOMIOpcode: 0x03,
+		// Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		// Object Context
+		OCBranch:   0x0c,
+		OCType:     0x0007,
+		OCLength:   4,
+		OCInstance: 0x00000000,
+		// Vc
+		VcBranch: 0x0a,
+		VcLeaf:   0x0002,
+		VcLength: 3,
+		// EC
+		ECLength: 2,
+		ECValue:  []byte{0x03, 0xe8},
+		// End
+		EndBranch: 0x00,
+	}
+
+	return tibitData
+}
diff --git a/internal/pkg/core/l2oam/msg_set_hbtx_template.go b/internal/pkg/core/l2oam/msg_set_hbtx_template.go
new file mode 100644
index 0000000..f319e52
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_set_hbtx_template.go
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+//GenerateSetHbtxTemplate generates "OAM/HBTx Template" message
+func GenerateSetHbtxTemplate() gopacket.SerializableLayer {
+
+	tibitData := &TOAMSetRequest{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OAM Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBit OLT Management Interface
+		TOMIOpcode: 0x03,
+		// Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		// Object Context
+		OCBranch:   0x0c,
+		OCType:     0x0007,
+		OCLength:   4,
+		OCInstance: 0x00000000,
+		// Vc
+		VcBranch: 0x0a,
+		VcLeaf:   0x0003,
+		VcLength: 35,
+		// EC
+		ECLength: 34,
+		ECValue: []byte{
+			0x01, 0x80, 0xc2, 0x00, 0x00, 0x02, 0xe8, 0xb4,
+			0x70, 0x70, 0x04, 0x07, 0x88, 0x09, 0x03, 0x00,
+			0x50, 0x00, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00,
+			0x1b, 0x04, 0xb0, 0x2a, 0xea, 0x15, 0x00, 0x00,
+			0x00, 0x23},
+		// End
+		EndBranch: 0x00,
+	}
+
+	return tibitData
+}
diff --git a/internal/pkg/core/l2oam/msg_set_ingress_port.go b/internal/pkg/core/l2oam/msg_set_ingress_port.go
new file mode 100644
index 0000000..d55efdc
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_set_ingress_port.go
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"encoding/binary"
+
+	"github.com/google/gopacket"
+	"github.com/google/gopacket/layers"
+)
+
+// GenerateIngressPort generates "Protocol Filter/Ingress Port" message
+func GenerateIngressPort(OCInstance uint32, isponport bool) gopacket.SerializableLayer {
+
+	var ponPort uint16 = 0x0007
+
+	if !isponport {
+		ponPort = 0x0e07
+	}
+
+	return &SetGenerteIngressPortreq{
+		//IEEE 1904.2
+		Opcode:     0x03,
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		//TiBiT OLT Management Interface
+		TOMIOpcode: 0x03,
+		//Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		//Object Context
+		OCBranch:   0x0c,
+		OCType:     0x0cff,
+		OCLength:   4,
+		OCInstance: OCInstance,
+		//Vc
+		VcBranch: 0xcf,
+		VcLeaf:   0x0002,
+		VcLength: 9,
+		//EC OC
+		ECOCLength1:  8,
+		ECOCBranch:   0x0c,
+		ECOCType:     ponPort,
+		ECOCLength2:  4,
+		ECOCInstance: 0x00000000,
+		//End
+		EndBranch: 0x00,
+	}
+
+}
+
+// SetGenerteIngressPortreq is a structure for a reqest of "Protocol Filter/Ingress Port" message
+type SetGenerteIngressPortreq struct {
+	layers.BaseLayer
+	Opcode uint8
+	Flags      uint16
+	OAMPDUCode uint8
+	OUId       []byte // Organizationally Unique Identifier: 2a:ea:15 (Tibit Communications)
+	TOMIOpcode uint8
+	CTBranch   uint8
+	CTType     uint16
+	CTLength   uint8
+	CTInstance uint32
+	OCBranch   uint8
+	OCType     uint16
+	OCLength   uint8
+	OCInstance uint32
+	VcBranch uint8
+	VcLeaf   uint16
+	VcLength uint8
+	ECOCLength1  uint8
+	ECOCBranch   uint8
+	ECOCType     uint16
+	ECOCLength2  uint8
+	ECOCInstance uint32
+	EndBranch uint8
+}
+
+// Len returns the length of SetGenerteIngressPortreq
+func (d *SetGenerteIngressPortreq) Len() int {
+	return 21 + int(d.CTLength) + int(d.OCLength) + int(d.VcLength)
+}
+
+// LayerType returns the ethernet type of SetGenerteIngressPortreq
+func (d *SetGenerteIngressPortreq) LayerType() gopacket.LayerType {
+	return layers.LayerTypeEthernet
+}
+
+// SerializeTo serializes a data structure to byte arrays
+func (d *SetGenerteIngressPortreq) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
+	plen := int(d.Len())
+	data, err := b.PrependBytes(plen)
+	if err != nil {
+		return err
+	}
+
+	i := 0
+	data[i] = byte(d.Opcode)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.Flags)
+	i += 2
+	data[i] = byte(d.OAMPDUCode)
+	i++
+	copy(data[i:i+len(d.OUId)], d.OUId)
+	i += len(d.OUId)
+	data[i] = byte(d.TOMIOpcode)
+	i++
+	data[i] = byte(d.CTBranch)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.CTType)
+	i += 2
+	data[i] = byte(d.CTLength)
+	i++
+	binary.BigEndian.PutUint32(data[i:i+4], d.CTInstance)
+	i += 4
+	data[i] = byte(d.OCBranch)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.OCType)
+	i += 2
+	data[i] = byte(d.OCLength)
+	i++
+	binary.BigEndian.PutUint32(data[i:i+4], d.OCInstance)
+	i += 4
+	data[i] = byte(d.VcBranch)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.VcLeaf)
+	i += 2
+	data[i] = byte(d.VcLength)
+	i++
+	data[i] = byte(d.ECOCLength1)
+	i++
+	data[i] = byte(d.ECOCBranch)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.ECOCType)
+	i += 2
+	data[i] = byte(d.ECOCLength2)
+	i++
+	binary.BigEndian.PutUint32(data[i:i+4], d.ECOCInstance)
+	i += 4
+	data[i] = byte(d.EndBranch)
+
+	return nil
+
+}
+
+// Decode decodes byte arrays to a data structure
+func (d *SetGenerteIngressPortreq) Decode(data []byte) error {
+	i := 0
+	d.Opcode = data[i]
+	i++
+	d.Flags = binary.BigEndian.Uint16(data[i : i+2])
+	i += 2
+	d.OAMPDUCode = data[i]
+	i++
+	d.OUId = data[i : i+3]
+	i += len(d.OUId)
+	d.TOMIOpcode = data[i]
+	i++
+	d.CTBranch = data[i]
+	i++
+	d.CTType = binary.BigEndian.Uint16(data[i : i+2])
+	i += 2
+	d.CTLength = data[i]
+	i++
+	d.CTInstance = binary.BigEndian.Uint32(data[i : i+4])
+	i += 4
+	d.OCBranch = data[i]
+	i++
+	d.OCType = binary.BigEndian.Uint16(data[i : i+2])
+	i += 2
+	d.OCLength = data[i]
+	i++
+	d.OCInstance = binary.BigEndian.Uint32(data[i : i+4])
+	i += 4
+	d.VcBranch = data[i]
+	i++
+	d.VcLeaf = binary.BigEndian.Uint16(data[i : i+2])
+	i += 2
+	d.VcLength = data[i]
+	i++
+	d.ECOCLength1 = data[i]
+	i++
+	d.ECOCBranch = data[i]
+	i++
+	d.ECOCType = binary.BigEndian.Uint16(data[i : i+2])
+	i += 2
+	d.ECOCLength2 = data[i]
+	i++
+	d.ECOCInstance = binary.BigEndian.Uint32(data[i : i+4])
+	i += 4
+	d.EndBranch = data[i]
+
+	return nil
+}
diff --git a/internal/pkg/core/l2oam/msg_set_management_lock.go b/internal/pkg/core/l2oam/msg_set_management_lock.go
new file mode 100644
index 0000000..c1490cf
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_set_management_lock.go
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GenerateSetManagementLock generates "Device/ManagementLock" message
+func GenerateSetManagementLock() gopacket.SerializableLayer {
+	tibitData := &TOAMSetRequest{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OAM Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBit OLT Management Interface
+		TOMIOpcode: 0x03,
+		// Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		// Object Context
+		OCBranch:   0x0c,
+		OCType:     0x0dce,
+		OCLength:   4,
+		OCInstance: 0x00000000,
+		// Vc
+		VcBranch: 0xde,
+		VcLeaf:   0x002e,
+		VcLength: 0x04,
+		// EC
+		ECLength: 1,
+		ECValue:  []byte{0x00},
+		ECList: []ECValueSet{
+			{
+				Length: 0x01,
+				Value:  []byte{0x02},
+			},
+		},
+		// End
+		EndBranch: 0x00,
+	}
+	return tibitData
+}
diff --git a/internal/pkg/core/l2oam/msg_set_mpcp_sync.go b/internal/pkg/core/l2oam/msg_set_mpcp_sync.go
new file mode 100644
index 0000000..bfa1d4d
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_set_mpcp_sync.go
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GenerateSetMPCPSync generates "MPCP/Sync Type" message
+func GenerateSetMPCPSync() gopacket.SerializableLayer {
+
+	tibitData := &TOAMSetRequest{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OAM Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBit OLT Management Interface
+		TOMIOpcode: 0x43,
+		// Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		// Object Context
+		OCBranch:   0x0c,
+		OCType:     0x0007,
+		OCLength:   4,
+		OCInstance: 0x00000000,
+		// Vc
+		VcBranch: 0xcc,
+		VcLeaf:   0x0004,
+		VcLength: 2,
+		// EC
+		ECLength: 1,
+		ECValue:  []byte{0x20},
+		// End
+		EndBranch: 0x00,
+	}
+	return tibitData
+}
diff --git a/internal/pkg/core/l2oam/msg_set_request_saved.go b/internal/pkg/core/l2oam/msg_set_request_saved.go
new file mode 100644
index 0000000..6869a79
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_set_request_saved.go
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+//
+func GenerateSetRequestSaved() gopacket.SerializableLayer {
+
+	tibitData := &TOAMSetRequest{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OAM Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBit OLT Management Interface
+		TOMIOpcode: 0x43,
+		// Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		// Object Context
+		OCBranch:   0x0c,
+		OCType:     0x0007,
+		OCLength:   4,
+		OCInstance: 0x00000000,
+		// Vc
+		VcBranch: 0xcc,
+		VcLeaf:   0x0004,
+		VcLength: 2,
+		// EC
+		ECLength: 1,
+		ECValue:  []byte{0x20},
+		// End
+		EndBranch: 0x00,
+	}
+	return tibitData
+}
diff --git a/internal/pkg/core/l2oam/msg_set_traffic_profile.go b/internal/pkg/core/l2oam/msg_set_traffic_profile.go
new file mode 100644
index 0000000..af11a66
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_set_traffic_profile.go
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GenerateSetTrafficProfile generates "Traffic Control/Traffic Profile" message
+func GenerateSetTrafficProfile(trafficControl []byte, trafficProfile []byte) gopacket.SerializableLayer {
+	tibitData := &setTrafficControlTrafficProfileReq{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OAM Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15},
+		// TiBit OLT Management Interface
+		TOMIOpcode: 0x03,
+		// Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		// Object Context
+		OCBranch:   0x0c,
+		OCType:     0x07c0,
+		OCLength:   4,
+		OCInstance: trafficControl,
+		// Vc
+		VcBranch: 0x7c,
+		VcLeaf:   0x0002,
+		VcLength: 9,
+		// EC OC
+		ECOC: []ECOCTrafficControlTrafficProfile{
+			{
+				EcOcLength:   8,
+				EcOcBranch:   0x0c,
+				EcOcType:     0x070f,
+				EcOcLength2:  4,
+				EcOcInstance: trafficProfile,
+			},
+		},
+		// End
+		EndBranch: 0x00,
+	}
+	return tibitData
+}
diff --git a/internal/pkg/core/l2oam/msg_toam_get.go b/internal/pkg/core/l2oam/msg_toam_get.go
new file mode 100644
index 0000000..f831aa0
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_toam_get.go
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"encoding/binary"
+	"encoding/hex"
+	"fmt"
+
+
+	"github.com/google/gopacket"
+	"github.com/google/gopacket/layers"
+)
+
+// TOAMGetRequest is a structure for GET request of TOAM message
+type TOAMGetRequest struct {
+	layers.BaseLayer
+	Opcode uint8
+	Flags      uint16
+	OAMPDUCode uint8
+	OUId       []byte // Organizationally Unique Identifier: 2a:ea:15 (Tibit Communications)
+	TOMIOpcode uint8
+	CTBranch   uint8
+	CTType     uint16
+	CTLength   uint8
+	CTInstance uint32
+	OCBranch   uint8
+	OCType     uint16
+	OCLength   uint8
+	OCInstance uint32
+	VdBranch uint8
+	VdLeaf   uint16
+	EndBranch uint8
+}
+
+// String returns the string expression of TOAMGetRequest
+func (d *TOAMGetRequest) String() string {
+	message := fmt.Sprintf("Opcode:%02x, Flags:%04x, OAMPDUCode:%02x, OUId:%v", d.Opcode, d.Flags, d.OAMPDUCode, hex.EncodeToString(d.OUId))
+	message = fmt.Sprintf("%s, TOMIOpcode:%02x", message, d.TOMIOpcode)
+	message = fmt.Sprintf("%s, CTBranch:%02x, CTType:%04x, CTLength:%02x, CTInstance:%08x", message, d.CTBranch, d.CTType, d.CTLength, d.CTInstance)
+	message = fmt.Sprintf("%s, OCBranch:%02x, OCType:%04x, OCLength:%02x, OCInstance:%08x", message, d.OCBranch, d.OCType, d.OCLength, d.OCInstance)
+	message = fmt.Sprintf("%s, VdBranch:%02x, VdLeaf:%04x, EndBranch:%02x", message, d.VdBranch, d.VdLeaf, d.EndBranch)
+	return message
+}
+
+// Len returns the length of TOAMGetRequest
+func (d *TOAMGetRequest) Len() int {
+	return 29
+}
+
+// LayerType returns the ethernet type of TOAMGetRequest
+func (d *TOAMGetRequest) LayerType() gopacket.LayerType { return layers.LayerTypeEthernet }
+
+// SerializeTo serializes a data structure to byte arrays
+func (d *TOAMGetRequest) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
+	plen := int(d.Len())
+	data, err := b.PrependBytes(plen)
+	if err != nil {
+		return err
+	}
+
+	i := 0
+	data[i] = byte(d.Opcode)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.Flags)
+	i += 2
+	data[i] = byte(d.OAMPDUCode)
+	i++
+	copy(data[i:i+len(d.OUId)], d.OUId)
+	i += len(d.OUId)
+	data[i] = byte(d.TOMIOpcode)
+	i++
+	data[i] = byte(d.CTBranch)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.CTType)
+	i += 2
+	data[i] = byte(d.CTLength)
+	i++
+	binary.BigEndian.PutUint32(data[i:i+4], d.CTInstance)
+	i += 4
+	data[i] = byte(d.OCBranch)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.OCType)
+	i += 2
+	data[i] = byte(d.OCLength)
+	i++
+	binary.BigEndian.PutUint32(data[i:i+4], d.OCInstance)
+	i += 4
+	data[i] = byte(d.VdBranch)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.VdLeaf)
+	i += 2
+	data[i] = byte(d.EndBranch)
+
+	return nil
+}
+
+// TOAMGetResponse is a structure for GET response of TOAM message
+type TOAMGetResponse struct {
+	layers.BaseLayer
+	Opcode uint8
+	Flags      uint16
+	OAMPDUCode uint8
+	OUId       []byte // Organizationally Unique Identifier: 2a:ea:15 (Tibit Communications)
+	TOMIOpcode uint8
+	CTBranch   uint8
+	CTType     uint16
+	CTLength   uint8
+	CTInstance uint32
+	OCBranch   uint8
+	OCType     uint16
+	OCLength   uint8
+	OCInstance uint32
+	VcBranch uint8
+	VcLeaf   uint16
+	VcLength uint8
+}
+
+// String returns the string expression of TOAMGetResponse
+func (d *TOAMGetResponse) String() string {
+	message := fmt.Sprintf("Opcode:%02x, Flags:%04x, OAMPDUCode:%02x, OUId:%v", d.Opcode, d.Flags, d.OAMPDUCode, hex.EncodeToString(d.OUId))
+	message = fmt.Sprintf("%s, TOMIOpcode:%02x", message, d.TOMIOpcode)
+	message = fmt.Sprintf("%s, CTBranch:%02x, CTType:%04x, CTLength:%02x, CTInstance:%08x", message, d.CTBranch, d.CTType, d.CTLength, d.CTInstance)
+	message = fmt.Sprintf("%s, OCBranch:%02x, OCType:%04x, OCLength:%02x, OCInstance:%08x", message, d.OCBranch, d.OCType, d.OCLength, d.OCInstance)
+	message = fmt.Sprintf("%s, VcBranch:%02x, VcLeaf:%04x, VcLength:%02x", message, d.VcBranch, d.VcLeaf, d.VcLength)
+	return message
+}
+
+// Len returns the length of TOAMGetResponse
+func (d *TOAMGetResponse) Len() int {
+	return 28
+}
+
+// LayerType returns the ethernet type of TOAMGetResponse
+func (d *TOAMGetResponse) LayerType() gopacket.LayerType { return layers.LayerTypeEthernet }
+
+// Decode decodes byte arrays to a data structure
+func (d *TOAMGetResponse) Decode(data []byte) {
+	i := 0
+	d.Opcode = data[i]
+	i++
+	d.Flags = binary.BigEndian.Uint16(data[i : i+2])
+	i += 2
+	d.OAMPDUCode = data[i]
+	i++
+	d.OUId = data[i : i+3]
+	i += len(d.OUId)
+	d.TOMIOpcode = data[i]
+	i++
+	d.CTBranch = data[i]
+	i++
+	d.CTType = binary.BigEndian.Uint16(data[i : i+2])
+	i += 2
+	d.CTLength = data[i]
+	i++
+	d.CTInstance = binary.BigEndian.Uint32(data[i : i+4])
+	i += 4
+	d.OCBranch = data[i]
+	i++
+	d.OCType = binary.BigEndian.Uint16(data[i : i+2])
+	i += 2
+	d.OCLength = data[i]
+	i++
+	d.OCInstance = binary.BigEndian.Uint32(data[i : i+4])
+	i += 4
+	d.VcBranch = data[i]
+	i++
+	d.VcLeaf = binary.BigEndian.Uint16(data[i : i+2])
+	i += 2
+	d.VcLength = data[i]
+}
diff --git a/internal/pkg/core/l2oam/msg_toam_set.go b/internal/pkg/core/l2oam/msg_toam_set.go
new file mode 100644
index 0000000..7aa6bec
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_toam_set.go
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"encoding/binary"
+	"encoding/hex"
+	"fmt"
+
+
+	"github.com/google/gopacket"
+	"github.com/google/gopacket/layers"
+)
+
+// TOAMSetRequest is a structure for SET request of TOAM message
+type TOAMSetRequest struct {
+	layers.BaseLayer
+	Opcode uint8
+	Flags      uint16
+	OAMPDUCode uint8
+	OUId       []byte // Organizationally Unique Identifier: 2a:ea:15 (Tibit Communications)
+	TOMIOpcode uint8
+	CTBranch   uint8
+	CTType     uint16
+	CTLength   uint8
+	CTInstance uint32
+	OCBranch   uint8
+	OCType     uint16
+	OCLength   uint8
+	OCInstance uint32
+	VcBranch uint8
+	VcLeaf   uint16
+	VcLength uint8
+	ECLength uint8
+	ECValue  []byte
+	ECList []ECValueSet
+	EndBranch uint8
+}
+
+// ECValueSet is a structure for Vc-EC object
+type ECValueSet struct {
+	Length uint8
+	Value  []byte
+}
+
+// String returns the string expression of TOAMSetRequest
+func (d *TOAMSetRequest) String() string {
+	message := fmt.Sprintf("Opcode:%x, Flags:%x, OAMPDUCode:%x, OUId:%v", d.Opcode, d.Flags, d.OAMPDUCode, hex.EncodeToString(d.OUId))
+	message = fmt.Sprintf("%s, TOMIOpcode:%x", message, d.TOMIOpcode)
+	message = fmt.Sprintf("%s, CTBranch:%x, CTType:%x, CTLength:%x, CTInstance:%x", message, d.CTBranch, d.CTType, d.CTLength, d.CTInstance)
+	message = fmt.Sprintf("%s, OCBranch:%x, OCType:%x, OCLength:%x, OCInstance:%x", message, d.OCBranch, d.OCType, d.OCLength, d.OCInstance)
+	message = fmt.Sprintf("%s, VcBranch:%x, VcLeaf:%x, VcLength:%x", message, d.VcBranch, d.VcLeaf, d.VcLength)
+	message = fmt.Sprintf("%s, ECLength:%x, ECValue:%v, EndBranch:%x", message, d.ECLength, hex.EncodeToString(d.ECValue), d.EndBranch)
+	return message
+}
+
+// Len returns the length of TOAMSetRequest
+func (d *TOAMSetRequest) Len() int {
+	if d.VcLength != 0x80 {
+		return 22 + int(d.CTLength) + int(d.OCLength) + int(d.VcLength)
+	}
+	return 22 + int(d.CTLength) + int(d.OCLength)
+
+}
+
+// LayerType returns the ethernet type of TOAMSetRequest
+func (d *TOAMSetRequest) LayerType() gopacket.LayerType { return layers.LayerTypeEthernet }
+
+// SerializeTo serializes a data structure to byte arrays
+func (d *TOAMSetRequest) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
+	plen := int(d.Len())
+	data, err := b.PrependBytes(plen)
+	if err != nil {
+		return err
+	}
+
+	i := 0
+	data[i] = byte(d.Opcode)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.Flags)
+	i += 2
+	data[i] = byte(d.OAMPDUCode)
+	i++
+	copy(data[i:i+len(d.OUId)], d.OUId)
+	i += len(d.OUId)
+	data[i] = byte(d.TOMIOpcode)
+	i++
+	data[i] = byte(d.CTBranch)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.CTType)
+	i += 2
+	data[i] = byte(d.CTLength)
+	i++
+	binary.BigEndian.PutUint32(data[i:i+4], d.CTInstance)
+	i += 4
+	data[i] = byte(d.OCBranch)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.OCType)
+	i += 2
+	data[i] = byte(d.OCLength)
+	i++
+	binary.BigEndian.PutUint32(data[i:i+4], d.OCInstance)
+	i += 4
+	data[i] = byte(d.VcBranch)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.VcLeaf)
+	i += 2
+	data[i] = byte(d.VcLength)
+	i++
+	if d.VcLength != 0x80 {
+		// EC
+		data[i] = byte(d.ECLength)
+		i++
+		copy(data[i:i+int(d.ECLength)], d.ECValue)
+		i += int(d.ECLength)
+	}
+	if d.ECList != nil {
+		for _, ecSet := range d.ECList {
+			data[i] = byte(ecSet.Length)
+			i++
+			copy(data[i:i+int(ecSet.Length)], ecSet.Value)
+			i += int(ecSet.Length)
+		}
+	}
+
+	data[i] = byte(d.EndBranch)
+
+	return nil
+}
+
+// TOAMSetResponse is a structure for SET response of TOAM message
+type TOAMSetResponse struct {
+	layers.BaseLayer
+	Opcode uint8
+	Flags      uint16
+	OAMPDUCode uint8
+	OUId       []byte // Organizationally Unique Identifier: 2a:ea:15 (Tibit Communications)
+	TOMIOpcode uint8
+	CTBranch   uint8
+	CTType     uint16
+	CTLength   uint8
+	CTInstance uint32
+	OCBranch   uint8
+	OCType     uint16
+	OCLength   uint8
+	OCInstance uint32
+	VcBranch      uint8
+	VcLeaf        uint16
+	VcTOMIResCode uint8
+	EndBranch uint8
+}
+
+// String returns the string expression of TOAMSetResponse
+func (d *TOAMSetResponse) String() string {
+	message := fmt.Sprintf("Opcode:%x, Flags:%x, OAMPDUCode:%x, OUId:%v", d.Opcode, d.Flags, d.OAMPDUCode, hex.EncodeToString(d.OUId))
+	message = fmt.Sprintf("%s, TOMIOpcode:%x", message, d.TOMIOpcode)
+	message = fmt.Sprintf("%s, CTBranch:%x, CTType:%x, CTLength:%x, CTInstance:%x", message, d.CTBranch, d.CTType, d.CTLength, d.CTInstance)
+	message = fmt.Sprintf("%s, OCBranch:%x, OCType:%x, OCLength:%x, OCInstance:%x", message, d.OCBranch, d.OCType, d.OCLength, d.OCInstance)
+	message = fmt.Sprintf("%s, VcBranch:%x, VcLeaf:%x, VcTOMIResCode:%x, EndBranch:%x", message, d.VcBranch, d.VcLeaf, d.VcTOMIResCode, d.EndBranch)
+	return message
+}
+
+// Len returns the length of TOAMSetResponse
+func (d *TOAMSetResponse) Len() int {
+	return 34 + int(d.CTLength) + int(d.OCLength)
+}
+
+// LayerType returns the ethernet type of TOAMSetResponse
+func (d *TOAMSetResponse) LayerType() gopacket.LayerType { return layers.LayerTypeEthernet }
+
+// Decode decodes byte arrays to a data structure
+func (d *TOAMSetResponse) Decode(data []byte) error {
+	i := 0
+	d.Opcode = data[i]
+	i++
+	d.Flags = binary.BigEndian.Uint16(data[i : i+2])
+	i += 2
+	d.OAMPDUCode = data[i]
+	i++
+	d.OUId = data[i : i+3]
+	i += len(d.OUId)
+	d.TOMIOpcode = data[i]
+	i++
+	d.CTBranch = data[i]
+	i++
+	d.CTType = binary.BigEndian.Uint16(data[i : i+2])
+	i += 2
+	d.CTLength = data[i]
+	i++
+	d.CTInstance = binary.BigEndian.Uint32(data[i : i+4])
+	i += 4
+	d.OCBranch = data[i]
+	i++
+	d.OCType = binary.BigEndian.Uint16(data[i : i+2])
+	i += 2
+	d.OCLength = data[i]
+	i++
+	d.OCInstance = binary.BigEndian.Uint32(data[i : i+4])
+	i += 4
+	d.VcBranch = data[i]
+	i++
+	d.VcLeaf = binary.BigEndian.Uint16(data[i : i+2])
+	i += 2
+	d.VcTOMIResCode = data[i]
+	i++
+	d.EndBranch = data[i]
+
+	return nil
+}
diff --git a/internal/pkg/core/l2oam/msg_traffic_control_traffic_profile.go b/internal/pkg/core/l2oam/msg_traffic_control_traffic_profile.go
new file mode 100644
index 0000000..84a325a
--- /dev/null
+++ b/internal/pkg/core/l2oam/msg_traffic_control_traffic_profile.go
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"encoding/binary"
+	"encoding/hex"
+	"fmt"
+
+	"github.com/google/gopacket"
+	"github.com/google/gopacket/layers"
+)
+
+// GenerateTrafficControlTrafficProfile generates "Traffic Control/Traffic Profile" message
+func GenerateTrafficControlTrafficProfile(trafficControl []byte, trafficProfile []byte) gopacket.SerializableLayer {
+
+	tibitData := &setTrafficControlTrafficProfileReq{
+		// IEEE 1904.2
+		Opcode: 0x03,
+		// OMI Protocol
+		Flags:      0x0050,
+		OAMPDUCode: 0xfe,
+		OUId:       []byte{0x2a, 0xea, 0x15}, // Organizationally Unique Identifier: 2a:ea:15 (Tibit Communications)
+		// TiBiT OLT Management Interface
+		TOMIOpcode: 0x03,
+		// Correlation Tag
+		CTBranch:   0x0c,
+		CTType:     0x0c7a,
+		CTLength:   4,
+		CTInstance: getOltInstance(),
+		// Object Context
+		OCBranch:   0x0c,
+		OCType:     0x07c0,
+		OCLength:   4,
+		OCInstance: trafficControl,
+		// Vc
+		VcBranch: 0x7c,
+		VcLeaf:   0x0002,
+		VcLength: 0x09,
+
+		//EC OC
+		ECOC: []ECOCTrafficControlTrafficProfile{{EcOcLength: 8, EcOcBranch: 0x0c, EcOcType: 0x070f, EcOcLength2: 4, EcOcInstance: trafficProfile}},
+
+		// End
+		EndBranch: 0x00,
+	}
+
+	return tibitData
+}
+
+type setTrafficControlTrafficProfileReq struct {
+	layers.BaseLayer
+	Opcode uint8
+	Flags      uint16
+	OAMPDUCode uint8
+	OUId       []byte // Organizationally Unique Identifier: 2a:ea:15 (Tibit Communications)
+	TOMIOpcode uint8
+	CTBranch   uint8
+	CTType     uint16
+	CTLength   uint8
+	CTInstance uint32
+	OCBranch   uint8
+	OCType     uint16
+	OCLength   uint8
+	OCInstance []byte
+	VcBranch uint8
+	VcLeaf   uint16
+	VcLength uint8
+
+	ECOC []ECOCTrafficControlTrafficProfile
+
+	EndBranch uint8
+}
+
+// ECOCTrafficControlTrafficProfile is a structure for Vc-EC OC object
+type ECOCTrafficControlTrafficProfile struct {
+	EcOcLength   uint8
+	EcOcBranch   uint8
+	EcOcType     uint16
+	EcOcLength2  uint8
+	EcOcInstance []byte
+}
+
+// String returns the string expression of setTrafficControlTrafficProfileReq
+func (d *setTrafficControlTrafficProfileReq) String() string {
+	message := fmt.Sprintf("Opcode:%x, Flags:%x, OAMPDUCode:%x, OUId:%v", d.Opcode, d.Flags, d.OAMPDUCode, hex.EncodeToString(d.OUId))
+	message = fmt.Sprintf("%s, TOMIOpcode:%x", message, d.TOMIOpcode)
+	message = fmt.Sprintf("%s, CTBranch:%x, CTType:%x, CTLength:%x, CTInstance:%x", message, d.CTBranch, d.CTType, d.CTLength, d.CTInstance)
+	message = fmt.Sprintf("%s, OCBranch:%x, OCType:%x, OCLength:%x, OCInstance:%x", message, d.OCBranch, d.OCType, d.OCLength, d.OCInstance)
+	message = fmt.Sprintf("%s, VcBranch:%x, VcLeaf:%x, VcLength:%x", message, d.VcBranch, d.VcLeaf, d.VcLength)
+	for _, ecoc := range d.ECOC {
+		message = fmt.Sprintf("%s, EcOcLength:%x, EcOcBranch:%v, EcOcType:%x, EcOcLength2:%x, EcOcInstance:%x, ", message, ecoc.EcOcLength, ecoc.EcOcBranch, ecoc.EcOcType, ecoc.EcOcLength2, hex.EncodeToString(ecoc.EcOcInstance))
+	}
+	message = fmt.Sprintf("%s, EndBranch:%x", message, d.EndBranch)
+	return message
+}
+
+// Len returns the length of setTrafficControlTrafficProfileReq
+func (d *setTrafficControlTrafficProfileReq) Len() int {
+	return 21 + int(d.CTLength) + int(d.OCLength) + int(d.VcLength)
+}
+
+// LayerType returns the ethernet type of setTrafficControlTrafficProfileReq
+func (d *setTrafficControlTrafficProfileReq) LayerType() gopacket.LayerType {
+	return layers.LayerTypeEthernet
+}
+
+// SerializeTo serializes a data structure to byte arrays
+func (d *setTrafficControlTrafficProfileReq) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
+	plen := int(d.Len())
+	data, err := b.PrependBytes(plen)
+	if err != nil {
+		return err
+	}
+
+	i := 0
+	data[i] = byte(d.Opcode)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.Flags)
+	i += 2
+	data[i] = byte(d.OAMPDUCode)
+	i++
+	copy(data[i:i+len(d.OUId)], d.OUId)
+	i += len(d.OUId)
+	data[i] = byte(d.TOMIOpcode)
+	i++
+	data[i] = byte(d.CTBranch)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.CTType)
+	i += 2
+	data[i] = byte(d.CTLength)
+	i++
+	binary.BigEndian.PutUint32(data[i:i+4], d.CTInstance)
+	i += 4
+	data[i] = byte(d.OCBranch)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.OCType)
+	i += 2
+	data[i] = byte(d.OCLength)
+	i++
+	copy(data[i:i+4], d.OCInstance)
+	i += 4
+	data[i] = byte(d.VcBranch)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], d.VcLeaf)
+	i += 2
+	data[i] = byte(d.VcLength)
+	i++
+	for _, ecoc := range d.ECOC {
+		nextIndex := SerializeECOC(&ecoc, data, i)
+		i = nextIndex
+	}
+
+	data[i] = byte(d.EndBranch)
+
+	return nil
+}
+
+// SerializeECOC serializes a "EC OC" structure to byte arrays
+func SerializeECOC(ecoc *ECOCTrafficControlTrafficProfile, data []byte, startIndex int) int {
+	i := startIndex
+	data[i] = byte(ecoc.EcOcLength)
+	i++
+	data[i] = byte(ecoc.EcOcBranch)
+	i++
+	binary.BigEndian.PutUint16(data[i:i+2], ecoc.EcOcType)
+	i += 2
+	data[i] = byte(ecoc.EcOcLength2)
+	i++
+	copy(data[i:i+int(ecoc.EcOcLength2)], ecoc.EcOcInstance)
+	i += int(ecoc.EcOcLength2)
+
+	return i
+}
diff --git a/internal/pkg/core/l2oam/onu_list_access.go b/internal/pkg/core/l2oam/onu_list_access.go
new file mode 100644
index 0000000..0ca4714
--- /dev/null
+++ b/internal/pkg/core/l2oam/onu_list_access.go
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"encoding/json"
+	"io/ioutil"
+	"os"
+)
+
+// JSON file name
+const jsonname = "/onu_list.json"
+
+// OnuStatus has ONU status
+type OnuStatus struct {
+	ID           string `json:"id"`
+	AdminState   string `json:"admin_state"`
+	OpeState     string `json:"ope_state"`
+	ConnectState string `json:"con_state"`
+	MacAddress   string `json:"mac_addr"`
+	RebootState  string `json:"reboot_state"`
+}
+
+// ReadOnuStatusList reads JSON file
+func ReadOnuStatusList() ([]OnuStatus, error) {
+	bytes, err := ioutil.ReadFile(os.Getenv("HOME") + jsonname)
+	if err != nil && os.IsNotExist(err) {
+		return nil, nil
+	}
+	var onuList []OnuStatus
+	if err := json.Unmarshal(bytes, &onuList); err != nil {
+		return nil, err
+	}
+	return onuList, nil
+}
+
+// WriteOnuStatusList writes JSON file
+func WriteOnuStatusList(list []OnuStatus) error {
+	bytes, err := json.Marshal(list)
+	if err != nil {
+		return err
+	}
+	return ioutil.WriteFile(os.Getenv("HOME")+jsonname, bytes, 0644)
+}
+
+// AddOnu adds ONU to ONU status list
+func AddOnu(sts *OnuStatus) error {
+	list, err := ReadOnuStatusList()
+	if err != nil {
+		return err
+	}
+	if list == nil {
+		newList := []OnuStatus{*sts}
+		return WriteOnuStatusList(newList)
+	}
+	return WriteOnuStatusList(append(list, *sts))
+}
+
+// UpdateOnu updates ONU status
+func UpdateOnu(upSts *OnuStatus) error {
+	list, err := ReadOnuStatusList()
+	if (err != nil) || (list == nil) {
+		return err
+	}
+	newList := []OnuStatus{}
+	for _, sts := range list {
+		if sts.ID == upSts.ID {
+			newList = append(newList, *upSts)
+		} else {
+			newList = append(newList, sts)
+		}
+	}
+	return WriteOnuStatusList(newList)
+}
+
+// RemoveOnu removes ONU from ONU status list
+func RemoveOnu(id string) error {
+	list, err := ReadOnuStatusList()
+	if (err != nil) || (list == nil) {
+		return err
+	}
+	newList := []OnuStatus{}
+	for _, sts := range list {
+		if sts.ID != id {
+			newList = append(newList, sts)
+		}
+	}
+	return WriteOnuStatusList(newList)
+}
+
+// GetOnuFromDeviceID returns ONU status from ONU status list using its device ID
+func GetOnuFromDeviceID(id string) (*OnuStatus, error) {
+	list, err := ReadOnuStatusList()
+	if err != nil {
+		return nil, err
+	}
+	if list == nil {
+		return nil, nil
+	}
+	for _, sts := range list {
+		if sts.ID != id {
+			return &sts, nil
+		}
+	}
+	return nil, nil
+}
+
+// GetOnuFromMacAddr returns ONU status from ONU status list using its MAC address
+func GetOnuFromMacAddr(addr string) (*OnuStatus, error) {
+	list, err := ReadOnuStatusList()
+	if err != nil {
+		return nil, err
+	}
+	if list == nil {
+		return nil, nil
+	}
+	for _, sts := range list {
+		if sts.MacAddress == addr {
+			return &sts, nil
+		}
+	}
+	return nil, nil
+}
diff --git a/internal/pkg/core/l2oam/onu_msg_get_onu_system_info.go b/internal/pkg/core/l2oam/onu_msg_get_onu_system_info.go
new file mode 100644
index 0000000..6dd13d8
--- /dev/null
+++ b/internal/pkg/core/l2oam/onu_msg_get_onu_system_info.go
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GenerateOnuSystemInfo generates "ONU System Information" message
+func GenerateOnuSystemInfo(PkgType string) gopacket.SerializableLayer {
+
+	if PkgType == OnuPkgTypeA {
+		//TypeA
+		data := &TibitFrame{
+			Data: []byte{
+				0x03, 0x00, 0x50, 0xfe, 0x00, 0x10, 0x00, 0x01,
+				0xd7, 0x00, 0x06, 0x00, 0x00,
+			},
+		}
+
+		return data
+	} else if PkgType == OnuPkgTypeB {
+		//TypeB
+		data := &TibitFrame{
+			Data: []byte{
+				0x03, 0x00, 0x50, 0xfe, 0x90, 0x82, 0x60, 0x00,
+				0xca, 0xfe, 0x00, 0xb7, 0x00, 0x40, 0x00, 0x00,
+			},
+		}
+
+		return data
+	}
+
+	return nil
+}
+
+// GetOnuSerialNo returns a serial number
+func GetOnuSerialNo(pkgType string, data []byte) string {
+	if pkgType == OnuPkgTypeA {
+		// 030050fe00100002 00 - 07
+		// d70006404d493920 08 - 15
+		// 32304b2042303041 16 - 23
+		// 3730204130302031 24 - 31
+		// 3730382020202020
+		// 2000000030313233
+		// 3435363730313233
+		// 3435363738394041
+		// 42434445
+		return string(data[20:26])
+	}
+	return ""
+}
+
+// GetOnuManufacture returns a manufacture information
+func GetOnuManufacture(pkgType string, data []byte) string {
+	if pkgType == OnuPkgTypeA {
+		if data[16] == 0x32 && data[17] == 0x30 && data[18] == 0x4b {
+			return "FURUKAWA"
+		}
+	}
+	return ""
+}
diff --git a/internal/pkg/core/l2oam/onu_msg_get_unip_info.go b/internal/pkg/core/l2oam/onu_msg_get_unip_info.go
new file mode 100644
index 0000000..f3efa24
--- /dev/null
+++ b/internal/pkg/core/l2oam/onu_msg_get_unip_info.go
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GenerateGetUnipInfo generates UnipInfo message
+func GenerateGetUnipInfo(pkgType string) gopacket.SerializableLayer {
+	if pkgType == OnuPkgTypeB {
+		return &TibitFrame{
+			Data: []byte{
+				0x03, 0x00, 0x50, 0xfe, 0x90, 0x82, 0x60, 0x00,
+				0xca, 0xfe, 0x00, 0xb6, 0x00, 0x01, 0x04, 0x00,
+				0x00, 0x00, 0x00, 0xb7, 0x00, 0x41,
+			},
+		}
+	}
+	return &TibitFrame{
+		Data: []byte{
+			0x03, 0x00, 0x50, 0xfe, 0x00, 0x10, 0x00, 0x01,
+			0xd6, 0x00, 0x03, 0x01, 0x00, 0x07, 0x00, 0x20,
+			0x07, 0x00, 0x5d, 0x07, 0x00, 0x5a, 0x07, 0x00,
+			0x4f, 0x07, 0x00, 0xa3, 0x07, 0x00, 0x1a, 0x07,
+			0x00, 0x47, 0x07, 0x00, 0xb0, 0x00, 0x00,
+		},
+	}
+}
diff --git a/internal/pkg/core/l2oam/onu_msg_set_dyn_learning_mode.go b/internal/pkg/core/l2oam/onu_msg_set_dyn_learning_mode.go
new file mode 100644
index 0000000..33c7a00
--- /dev/null
+++ b/internal/pkg/core/l2oam/onu_msg_set_dyn_learning_mode.go
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GenerateDynLearningMode generates "Dyn Learning Mode" message
+func GenerateDynLearningMode(PkgType string, index int) gopacket.SerializableLayer {
+
+	if PkgType == OnuPkgTypeA {
+		//TypeA
+		if index == 1 {
+			data := &TibitFrame{
+				Data: []byte{
+					0x03, 0x00, 0x50, 0xfe, 0x00, 0x10, 0x00, 0x01,
+					0xd6, 0x00, 0x03, 0x01, 0x00, 0xd7, 0x01, 0x01,
+					0x00, 0x00,
+				},
+			}
+			return data
+		} else if index == 2 {
+			data := &TibitFrame{
+				Data: []byte{
+					0x03, 0x00, 0x50, 0xfe, 0x00, 0x10, 0x00, 0x03,
+					0xd6, 0x00, 0x03, 0x01, 0x00, 0xd7, 0x01, 0x02,
+					0x07, 0xd0, 0x00, 0x00,
+				},
+			}
+			return data
+		} else if index == 3 {
+			data := &TibitFrame{
+				Data: []byte{
+					0x03, 0x00, 0x50, 0xfe, 0x00, 0x10, 0x00, 0x01,
+					0xd6, 0x00, 0x03, 0x01, 0x00, 0xd7, 0x01, 0x03,
+					0x00, 0x00,
+				},
+			}
+			return data
+		}
+
+	} else if PkgType == OnuPkgTypeB {
+		//TypeB
+		data := &TibitFrame{
+			Data: []byte{
+				0x03, 0x00, 0x50, 0xfe, 0x90, 0x82, 0x60, 0x00,
+				0xca, 0xfe, 0x00, 0xb6, 0x00, 0x01, 0x04, 0x01,
+				0x00, 0x00, 0x01, 0xb7, 0x00, 0x1c, 0x00, 0x00,
+			},
+		}
+
+		return data
+	}
+
+	return nil
+}
diff --git a/internal/pkg/core/l2oam/onu_msg_set_encryption_mode.go b/internal/pkg/core/l2oam/onu_msg_set_encryption_mode.go
new file mode 100644
index 0000000..599e8d4
--- /dev/null
+++ b/internal/pkg/core/l2oam/onu_msg_set_encryption_mode.go
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GenerateEncryptionMode generates "Encryption Mode" message
+func GenerateEncryptionMode(PkgType string, index int) gopacket.SerializableLayer {
+
+	if PkgType == OnuPkgTypeA {
+		//TypeA
+		if index == 1 {
+			data := &TibitFrame{
+				Data: []byte{
+					0x03, 0x00, 0x50, 0xfe, 0x00, 0x10, 0x00, 0x03,
+					0xd6, 0x00, 0x02, 0x01, 0x00, 0xd7, 0x04, 0x01,
+					0x02, 0x01, 0x2c, 0x00, 0x00,
+				},
+			}
+			return data
+		} else if index == 2 {
+			data := &TibitFrame{
+				Data: []byte{
+					0x03, 0x00, 0x50, 0xfe, 0x00, 0x10, 0x00, 0x03,
+					0xd6, 0x00, 0x02, 0x01, 0x00, 0xd7, 0x04, 0x02,
+					0x01, 0x02, 0x00, 0x00,
+				},
+			}
+			return data
+		}
+	} else if PkgType == OnuPkgTypeB {
+		//TypeB
+		if index == 1 {
+			data := &TibitFrame{
+				Data: []byte{
+					0x03, 0x00, 0x50, 0xfe, 0x90, 0x82, 0x60, 0x03,
+					0xca, 0xfe, 0x00, 0xb7, 0x00, 0x01, 0x01, 0x02,
+				},
+			}
+			return data
+		}
+	}
+
+	return nil
+}
diff --git a/internal/pkg/core/l2oam/onu_msg_set_fec_mode.go b/internal/pkg/core/l2oam/onu_msg_set_fec_mode.go
new file mode 100644
index 0000000..22712ad
--- /dev/null
+++ b/internal/pkg/core/l2oam/onu_msg_set_fec_mode.go
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GenerateFecMode generates "FEC Mode" message
+func GenerateFecMode(PkgType string) gopacket.SerializableLayer {
+
+	if PkgType == OnuPkgTypeA {
+		//TypeA
+		data := &TibitFrame{
+			Data: []byte{
+				0x03, 0x00, 0x50, 0xFE, 0x00, 0x10, 0x00, 0x03,
+				0xD6, 0x00, 0x02, 0x01, 0x00, 0xD7, 0x06, 0x05,
+				0x02, 0x01, 0x01,
+			},
+		}
+		return data
+	} else if PkgType == OnuPkgTypeB {
+		//TypeB
+		data := &TibitFrame{
+			Data: []byte{
+				0x03, 0x00, 0x50, 0xfe, 0x90, 0x82, 0x60, 0x03,
+				0xca, 0xfe, 0x00, 0xb7, 0x00, 0x16, 0x01, 0x01,
+			},
+		}
+
+		return data
+	}
+
+	return nil
+}
diff --git a/internal/pkg/core/l2oam/onu_msg_set_onu_config.go b/internal/pkg/core/l2oam/onu_msg_set_onu_config.go
new file mode 100644
index 0000000..e648138
--- /dev/null
+++ b/internal/pkg/core/l2oam/onu_msg_set_onu_config.go
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GenerateOnuConfig generates "ONU Config" message
+func GenerateOnuConfig(PkgType string) gopacket.SerializableLayer {
+
+	if PkgType == OnuPkgTypeA {
+		//TypeA
+
+		return nil
+	} else if PkgType == OnuPkgTypeB {
+		//TypeB
+		data := &TibitFrame{
+			Data: []byte{
+				0x03, 0x00, 0x50, 0xfe, 0x90, 0x82, 0x60, 0x00,
+				0xca, 0xfe, 0x00, 0xb7, 0x00, 0x45, 0x00, 0x00,
+			},
+		}
+		return data
+	}
+
+	return nil
+}
diff --git a/internal/pkg/core/l2oam/onu_msg_set_onu_errored_frame_threshold.go b/internal/pkg/core/l2oam/onu_msg_set_onu_errored_frame_threshold.go
new file mode 100644
index 0000000..2649171
--- /dev/null
+++ b/internal/pkg/core/l2oam/onu_msg_set_onu_errored_frame_threshold.go
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GenerateOnuErroredFrameThreshold generates "Errored Frame Threshold" message
+func GenerateOnuErroredFrameThreshold(PkgType string) gopacket.SerializableLayer {
+
+	if PkgType == OnuPkgTypeA {
+
+		return nil
+
+	} else if PkgType == OnuPkgTypeB {
+
+		return &TibitFrame{Data: []byte{
+			0x03, 0x00, 0x50, 0xfe, 0x90, 0x82, 0x60, 0x03,
+			0xca, 0xfe, 0x00, 0xb7, 0x00, 0x0d, 0x04, 0x00,
+			0x00, 0xff, 0xff,
+		}}
+
+	}
+
+	return nil
+}
diff --git a/internal/pkg/core/l2oam/onu_msg_set_onu_errored_frame_window.go b/internal/pkg/core/l2oam/onu_msg_set_onu_errored_frame_window.go
new file mode 100644
index 0000000..fa02acd
--- /dev/null
+++ b/internal/pkg/core/l2oam/onu_msg_set_onu_errored_frame_window.go
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GenerateOnuErroredFrameWindow generates "Errored Frame Window" message
+func GenerateOnuErroredFrameWindow(PkgType string) gopacket.SerializableLayer {
+
+	if PkgType == OnuPkgTypeA {
+
+		return nil
+
+	} else if PkgType == OnuPkgTypeB {
+
+		return &TibitFrame{Data: []byte{
+			0x03, 0x00, 0x50, 0xfe, 0x90, 0x82, 0x60, 0x03,
+			0xca, 0xfe, 0x00, 0xb7, 0x00, 0x0c, 0x02, 0x00,
+			0x0a,
+		}}
+
+	}
+
+	return nil
+}
diff --git a/internal/pkg/core/l2oam/onu_msg_set_onu_priority_queue_count.go b/internal/pkg/core/l2oam/onu_msg_set_onu_priority_queue_count.go
new file mode 100644
index 0000000..e868f9c
--- /dev/null
+++ b/internal/pkg/core/l2oam/onu_msg_set_onu_priority_queue_count.go
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GenerateOnuPriorityQueueCount generates "Priority Queue Count" message
+func GenerateOnuPriorityQueueCount(PkgType string, index int) gopacket.SerializableLayer {
+
+	if PkgType == OnuPkgTypeA {
+		//TypeA
+		if index == 1 {
+			data := &TibitFrame{
+				Data: []byte{
+					0x03, 0x00, 0x50, 0xfe, 0x00, 0x10, 0x00, 0x01,
+					0xd7, 0x00, 0x0a, 0x00, 0x00,
+				},
+			}
+			return data
+		} else if index == 2 {
+			data := &TibitFrame{
+				Data: []byte{
+					0x03, 0x00, 0x50, 0xfe, 0x00, 0x10, 0x00, 0x03,
+					0xd6, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
+					0xd7, 0x01, 0x0d, 0x08, 0x01, 0x01, 0xd0, 0x02,
+					0x01, 0xd0, 0x01, 0x32, 0x00, 0x00,
+				},
+			}
+			return data
+		}
+	} else if PkgType == OnuPkgTypeB {
+		//TypeB
+
+		data := &TibitFrame{
+			Data: []byte{
+				0x03, 0x00, 0x50, 0xfe, 0x90, 0x82, 0x60, 0x03,
+				0xca, 0xfe, 0x00, 0xb7, 0x00, 0x01, 0x01, 0x02,
+			},
+		}
+
+		return data
+	}
+
+	return nil
+}
diff --git a/internal/pkg/core/l2oam/onu_msg_set_ponp_opt_rx_input_power.go b/internal/pkg/core/l2oam/onu_msg_set_ponp_opt_rx_input_power.go
new file mode 100644
index 0000000..8c498f2
--- /dev/null
+++ b/internal/pkg/core/l2oam/onu_msg_set_ponp_opt_rx_input_power.go
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GeneratePonpOptRxInputPower generates "Ponp Optical Rx Input Power" message
+func GeneratePonpOptRxInputPower(PkgType string) gopacket.SerializableLayer {
+
+	if PkgType == OnuPkgTypeA {
+		//TypeA
+		data := &TibitFrame{
+			Data: []byte{
+				0x03, 0x00, 0x50, 0xFE, 0x00, 0x10, 0x00, 0x01,
+				0xD6, 0x00, 0x01, 0x01, 0x00, 0xD7, 0x02, 0x21,
+				0x00, 0x00,
+			},
+		}
+		return data
+	} else if PkgType == OnuPkgTypeB {
+		//TypeB
+		data := &TibitFrame{
+			Data: []byte{
+				0x03, 0x00, 0x50, 0xfe, 0x90, 0x82, 0x60, 0x00,
+				0xca, 0xfe, 0x00, 0xb6, 0x00, 0x01, 0x04, 0x01,
+				0x00, 0x00, 0x01, 0xb7, 0x00, 0x34, 0x00, 0x00,
+			},
+		}
+
+		return data
+	}
+
+	return nil
+}
diff --git a/internal/pkg/core/l2oam/onu_msg_set_ponp_opt_trx_supply_voltage.go b/internal/pkg/core/l2oam/onu_msg_set_ponp_opt_trx_supply_voltage.go
new file mode 100644
index 0000000..0fd9d15
--- /dev/null
+++ b/internal/pkg/core/l2oam/onu_msg_set_ponp_opt_trx_supply_voltage.go
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GeneratePonpOptTRxSupplyVoltage generates "Ponp Optical TRx Supply Voltage" message
+func GeneratePonpOptTRxSupplyVoltage(PkgType string) gopacket.SerializableLayer {
+
+	if PkgType == OnuPkgTypeA {
+		//TypeA
+		data := &TibitFrame{
+			Data: []byte{
+				0x03, 0x00, 0x50, 0xFE, 0x00, 0x10, 0x00, 0x01,
+				0xD6, 0x00, 0x01, 0x01, 0x00, 0xD7, 0x02, 0x1E,
+				0x00, 0x00,
+			},
+		}
+		return data
+	} else if PkgType == OnuPkgTypeB {
+		//TypeB
+		data := &TibitFrame{
+			Data: []byte{
+				0x03, 0x00, 0x50, 0xfe, 0x90, 0x82, 0x60, 0x00,
+				0xca, 0xfe, 0x00, 0xb7, 0x00, 0x31, 0x00, 0x00,
+			},
+		}
+
+		return data
+	}
+
+	return nil
+}
diff --git a/internal/pkg/core/l2oam/onu_msg_set_ponp_opt_tx_bias_current.go b/internal/pkg/core/l2oam/onu_msg_set_ponp_opt_tx_bias_current.go
new file mode 100644
index 0000000..e0edf9b
--- /dev/null
+++ b/internal/pkg/core/l2oam/onu_msg_set_ponp_opt_tx_bias_current.go
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GeneratePonpOptTxBiasCurrent generates "Ponp Optical Tx Bias Current" message
+func GeneratePonpOptTxBiasCurrent(PkgType string) gopacket.SerializableLayer {
+
+	if PkgType == OnuPkgTypeA {
+		//TypeA
+		data := &TibitFrame{
+			Data: []byte{
+				0x03, 0x00, 0x50, 0xFE, 0x00, 0x10, 0x00, 0x01,
+				0xD6, 0x00, 0x01, 0x01, 0x00, 0xD7, 0x02, 0x1F,
+				0x00, 0x00,
+			},
+		}
+		return data
+	} else if PkgType == OnuPkgTypeB {
+		//TypeB
+		data := &TibitFrame{
+			Data: []byte{
+				0x03, 0x00, 0x50, 0xfe, 0x90, 0x82, 0x60, 0x00,
+				0xca, 0xfe, 0x00, 0xb6, 0x00, 0x01, 0x04, 0x01,
+				0x00, 0x00, 0x01, 0xb7, 0x00, 0x32, 0x00, 0x00,
+			},
+		}
+
+		return data
+	}
+
+	return nil
+}
diff --git a/internal/pkg/core/l2oam/onu_msg_set_ponp_opt_tx_output_power.go b/internal/pkg/core/l2oam/onu_msg_set_ponp_opt_tx_output_power.go
new file mode 100644
index 0000000..7112c7d
--- /dev/null
+++ b/internal/pkg/core/l2oam/onu_msg_set_ponp_opt_tx_output_power.go
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GeneratePonpOptTxOutputPower generates "Ponp Optical Tx Output Power" message
+func GeneratePonpOptTxOutputPower(PkgType string) gopacket.SerializableLayer {
+
+	if PkgType == OnuPkgTypeA {
+		//TypeA
+		data := &TibitFrame{
+			Data: []byte{
+				0x03, 0x00, 0x50, 0xFE, 0x00, 0x10, 0x00, 0x01,
+				0xD6, 0x00, 0x01, 0x01, 0x00, 0xD7, 0x02, 0x20,
+				0x00, 0x00,
+			},
+		}
+		return data
+	} else if PkgType == OnuPkgTypeB {
+		//TypeB
+		data := &TibitFrame{
+			Data: []byte{
+				0x03, 0x00, 0x50, 0xfe, 0x90, 0x82, 0x60, 0x00,
+				0xca, 0xfe, 0x00, 0xb6, 0x00, 0x01, 0x04, 0x01,
+				0x00, 0x00, 0x01, 0xb7, 0x00, 0x33, 0x00, 0x00,
+			},
+		}
+
+		return data
+	}
+
+	return nil
+}
diff --git a/internal/pkg/core/l2oam/onu_msg_set_ponp_temperature.go b/internal/pkg/core/l2oam/onu_msg_set_ponp_temperature.go
new file mode 100644
index 0000000..2f9064c
--- /dev/null
+++ b/internal/pkg/core/l2oam/onu_msg_set_ponp_temperature.go
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GeneratePonpTemperature generates "Ponp Temerature" message
+func GeneratePonpTemperature(PkgType string) gopacket.SerializableLayer {
+
+	if PkgType == OnuPkgTypeA {
+		//TypeA 最後尾に0追加
+		data := &TibitFrame{
+			Data: []byte{
+				0x03, 0x00, 0x50, 0xFE, 0x00, 0x10, 0x00, 0x01,
+				0xD6, 0x00, 0x01, 0x01, 0x00, 0xD7, 0x02, 0x1D,
+				0x00, 0x00,
+			},
+		}
+		return data
+	} else if PkgType == OnuPkgTypeB {
+		//TypeB
+		data := &TibitFrame{
+			Data: []byte{
+				0x03, 0x00, 0x50, 0xfe, 0x90, 0x82, 0x60, 0x00,
+				0xca, 0xfe, 0x00, 0xb6, 0x00, 0x01, 0x04, 0x01,
+				0x00, 0x00, 0x01, 0xb7, 0x00, 0x30, 0x00, 0x00,
+			},
+		}
+
+		return data
+	}
+
+	return nil
+}
diff --git a/internal/pkg/core/l2oam/onu_msg_set_qos_policer_burst.go b/internal/pkg/core/l2oam/onu_msg_set_qos_policer_burst.go
new file mode 100644
index 0000000..ce83c6e
--- /dev/null
+++ b/internal/pkg/core/l2oam/onu_msg_set_qos_policer_burst.go
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GenerateSetQosPolicerBurst generates QosPolicerBurst message
+func GenerateSetQosPolicerBurst(pkgType string) gopacket.SerializableLayer {
+	if pkgType == OnuPkgTypeB {
+		return &TibitFrame{
+			Data: []byte{
+				0x03, 0x00, 0x50, 0xfe, 0x90, 0x82, 0x60, 0x03,
+				0xca, 0xfe, 0x00, 0xb7, 0x00, 0x10, 0x08, 0x40,
+				0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+			},
+		}
+	}
+	return &TibitFrame{
+		Data: []byte{
+			0x03, 0x00, 0x50, 0xFE, 0x00, 0x10, 0x00, 0x03,
+			0xD6, 0x00, 0x01, 0x01, 0x00, 0xD7, 0x06, 0x01,
+			0x00, 0x00, 0x4E, 0x20, 0x00, 0x00,
+		},
+	}
+
+}
diff --git a/internal/pkg/core/l2oam/onu_msg_set_qos_policer_rate.go b/internal/pkg/core/l2oam/onu_msg_set_qos_policer_rate.go
new file mode 100644
index 0000000..d343366
--- /dev/null
+++ b/internal/pkg/core/l2oam/onu_msg_set_qos_policer_rate.go
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GenerateSetQosPolicerRate generates QosPolicerRate message
+func GenerateSetQosPolicerRate(pkgType string, idx int) gopacket.SerializableLayer {
+	if pkgType == OnuPkgTypeB {
+		return &TibitFrame{
+			Data: []byte{
+				0x03, 0x00, 0x50, 0xfe, 0x90, 0x82, 0x60, 0x03,
+				0xca, 0xfe, 0x00, 0xb7, 0x00, 0x0F, 0x20, 0x00,
+				0x01, 0x86, 0xa0, 0x00, 0x01, 0x86, 0xa0, 0x00,
+				0x01, 0x86, 0xa0, 0x00, 0x01, 0x86, 0xa0, 0x00,
+				0x01, 0x86, 0xa0, 0x00, 0x01, 0x86, 0xa0, 0x00,
+				0x01, 0x86, 0xa0, 0x00, 0x01, 0x86, 0xa0,
+			},
+		}
+	}
+	switch idx {
+	case 1:
+		return &TibitFrame{
+			Data: []byte{
+				0x03, 0x00, 0x50, 0xfe, 0x00, 0x10, 0x00, 0x03,
+				0xd6, 0x00, 0x03, 0x01, 0x00, 0xd7, 0x06, 0x02,
+				0x0a, 0xff, 0x00, 0x01, 0x00, 0x00, 0x04,
+			},
+		}
+	case 2:
+		return &TibitFrame{
+			Data: []byte{
+				0x03, 0x00, 0x50, 0xFE, 0x00, 0x10, 0x00, 0x03,
+				0xD6, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xD7,
+				0x00, 0x24,
+			},
+		}
+	case 3:
+		return &TibitFrame{
+			Data: []byte{
+				0x03, 0x00, 0x50, 0xFE, 0x00, 0x10, 0x00, 0x03,
+				0xD6, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xD7,
+				0x00, 0x25,
+			},
+		}
+	case 4:
+		return &TibitFrame{
+			Data: []byte{
+				0x03, 0x00, 0x50, 0xFE, 0x00, 0x10, 0x00, 0x03,
+				0xD6, 0x00, 0x03, 0x00, 0xD7, 0x06, 0x02, 0x0A,
+				0xFF, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x00,
+			},
+		}
+	case 5:
+		return &TibitFrame{
+			Data: []byte{
+				0x03, 0x00, 0x50, 0xFE, 0x00, 0x10, 0x00, 0x03,
+				0xD6, 0x00, 0x03, 0x00, 0xD7, 0x06, 0x03, 0x07,
+				0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+			},
+		}
+	default:
+		return &TibitFrame{
+			Data: []byte{},
+		}
+	}
+}
diff --git a/internal/pkg/core/l2oam/onu_msg_set_reset_onu.go b/internal/pkg/core/l2oam/onu_msg_set_reset_onu.go
new file mode 100644
index 0000000..f204ba7
--- /dev/null
+++ b/internal/pkg/core/l2oam/onu_msg_set_reset_onu.go
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GenerateSetResetOnu generates reset ONU message
+func GenerateSetResetOnu(pkgType string) gopacket.SerializableLayer {
+	if pkgType == OnuPkgTypeB {
+		return &TibitFrame{
+			Data: []byte{
+				0x03, 0x00, 0x50, 0xfe, 0x90, 0x82, 0x60, 0x03,
+				0xca, 0xfe, 0x00, 0xb9, 0x00, 0x0e, 0x01, 0x01,
+				0x00, 0x00,
+			},
+		}
+	}
+	return &TibitFrame{
+		Data: []byte{
+			0x03, 0x00, 0x50, 0xfe, 0x00, 0x10, 0x00, 0x03,
+			0xd6, 0x00, 0x00, 0xd9, 0x00, 0x01, 0x80, 0x00,
+			0x00,
+		},
+	}
+
+}
diff --git a/internal/pkg/core/l2oam/onu_msg_set_traffic_enable.go b/internal/pkg/core/l2oam/onu_msg_set_traffic_enable.go
new file mode 100644
index 0000000..bdfdeed
--- /dev/null
+++ b/internal/pkg/core/l2oam/onu_msg_set_traffic_enable.go
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GenerateSetTrafficEnable generates "Traffic Enable" message
+func GenerateSetTrafficEnable(pkgType string) gopacket.SerializableLayer {
+	return &TibitFrame{
+		Data: []byte{
+			0x03, 0x00, 0x50, 0xfe, 0x00, 0x10, 0x00, 0x03,
+			0xd6, 0x00, 0x02, 0x01, 0x00, 0xd9, 0x06, 0x01,
+			0x80,
+		},
+	}
+}
diff --git a/internal/pkg/core/l2oam/onu_msg_set_unip_link_mode.go b/internal/pkg/core/l2oam/onu_msg_set_unip_link_mode.go
new file mode 100644
index 0000000..7054436
--- /dev/null
+++ b/internal/pkg/core/l2oam/onu_msg_set_unip_link_mode.go
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GenerateSetUnipLinkMode generates UnipLinkMode message
+func GenerateSetUnipLinkMode(pkgType string) gopacket.SerializableLayer {
+	if pkgType == OnuPkgTypeB {
+		return &TibitFrame{
+			Data: []byte{
+				0x03, 0x00, 0x50, 0xfe, 0x90, 0x82, 0x60, 0x03,
+				0xca, 0xfe, 0x00, 0xb6, 0x00, 0x01, 0x04, 0x00,
+				0x00, 0x00, 0x00, 0xb7, 0x00, 0x11, 0x01, 0x24,
+			},
+		}
+	}
+	return &TibitFrame{
+		Data: []byte{
+			0x03, 0x00, 0x50, 0xFE, 0x00, 0x10, 0x00, 0x03,
+			0xD6, 0x00, 0x03, 0x01, 0x00, 0xD7, 0x01, 0x05,
+			0x04, 0x00, 0xDF,
+		},
+	}
+
+}
diff --git a/internal/pkg/core/l2oam/onu_msg_set_unip_target_queue_priority.go b/internal/pkg/core/l2oam/onu_msg_set_unip_target_queue_priority.go
new file mode 100644
index 0000000..0947405
--- /dev/null
+++ b/internal/pkg/core/l2oam/onu_msg_set_unip_target_queue_priority.go
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GenerateUnipTargetQueuePriority generates "UnipTargetQueuePriority" message
+func GenerateUnipTargetQueuePriority(PkgType string) gopacket.SerializableLayer {
+
+	if PkgType == OnuPkgTypeA {
+		//TypeA
+
+		return nil
+	} else if PkgType == OnuPkgTypeB {
+		//TypeB
+
+		data := &TibitFrame{
+			Data: []byte{
+				0x03, 0x00, 0x50, 0xfe, 0x90, 0x82, 0x60, 0x03,
+				0xca, 0xfe, 0x00, 0xb7, 0x00, 0x43, 0x08, 0x00,
+				0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+			},
+		}
+
+		return data
+	}
+
+	return nil
+}
diff --git a/internal/pkg/core/l2oam/onu_msg_set_unip_toscos_conversion.go b/internal/pkg/core/l2oam/onu_msg_set_unip_toscos_conversion.go
new file mode 100644
index 0000000..a1f3abe
--- /dev/null
+++ b/internal/pkg/core/l2oam/onu_msg_set_unip_toscos_conversion.go
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GenerateUnipTOSCOSConversion generates "Unip TOSCOS Conversion" message
+func GenerateUnipTOSCOSConversion(PkgType string) gopacket.SerializableLayer {
+
+	if PkgType == OnuPkgTypeA {
+
+		return nil
+
+	} else if PkgType == OnuPkgTypeB {
+
+		return &TibitFrame{Data: []byte{
+			0x03, 0x00, 0x50, 0xfe, 0x90, 0x82, 0x60, 0x03,
+			0xca, 0xfe, 0x00, 0xb7, 0x00, 0x35, 0x08, 0x00,
+			0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+		}}
+	}
+
+	return nil
+}
diff --git a/internal/pkg/core/l2oam/onu_msg_set_vlan_pon_vid_value.go b/internal/pkg/core/l2oam/onu_msg_set_vlan_pon_vid_value.go
new file mode 100644
index 0000000..416dd69
--- /dev/null
+++ b/internal/pkg/core/l2oam/onu_msg_set_vlan_pon_vid_value.go
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GenerateSetVlanPonVIDValue generates VlanPonVIDValue message
+func GenerateSetVlanPonVIDValue(pkgType string, idx int, iTpidValue []byte, iVidValue []byte) gopacket.SerializableLayer {
+
+	if pkgType == OnuPkgTypeB {
+		tibitData := &TibitFrame{
+			Data: []byte{
+				0x03, 0x00, 0x50, 0xfe, 0x90, 0x82, 0x60, 0x03,
+				0xca, 0xfe, 0x00, 0xb7, 0x00, 0x15, 0x02,
+			},
+		}
+
+		tibitData.Data = append(tibitData.Data, iVidValue...)
+
+		return tibitData
+	}
+	switch idx {
+	case 1: // Downstream Rule
+		tibitData := &TibitFrame{
+			Data: []byte{
+				0x03, 0x00, 0x50, 0xfe, 0x00, 0x10, 0x00, 0x03,
+				0xd6, 0x00, 0x03, 0x01, 0x00, 0xd7, 0x05, 0x01,
+				0x02, 0x01, 0x0a, 0xd7, 0x05, 0x01, 0x07, 0x02,
+				0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0xd7, 0x05,
+				0x01, 0x02, 0x03, 0x02, 0xd7, 0x05, 0x01, 0x0b,
+				0x03, 0x04, 0x08, 0x00, 0x00, 0x00, 0x04,
+			},
+		}
+
+		// itpid must be 4 bytes length
+		tibitData.Data = append(tibitData.Data, iTpidValue...)
+		// ivid must be 2 bytes length
+		tibitData.Data = append(tibitData.Data, iVidValue...)
+
+		bytes := []byte{
+			0xd7, 0x05, 0x01, 0x04, 0x03, 0x07, 0x08, 0x00,
+			0xd7, 0x05, 0x01, 0x01, 0x00, 0xd9, 0x05, 0x02,
+			0x80, 0x00,
+		}
+
+		tibitData.Data = append(tibitData.Data, bytes...)
+
+		return tibitData
+
+	case 2: // Upstream Rule
+		tibitData := &TibitFrame{
+			Data: []byte{
+				0x03, 0x00, 0x50, 0xfe, 0x00, 0x10, 0x00, 0x03,
+				0xd6, 0x00, 0x01, 0x01, 0x00, 0xd7, 0x05, 0x01,
+				0x02, 0x01, 0x0a, 0xd7, 0x05, 0x01, 0x07, 0x02,
+				0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0xd7, 0x05,
+				0x01, 0x02, 0x03, 0x02, 0xd7, 0x05, 0x01, 0x0b,
+				0x03, 0x04, 0x08, 0x00, 0x00, 0x00, 0x04,
+			},
+		}
+
+		// itpid must be 4 bytes length
+		tibitData.Data = append(tibitData.Data, iTpidValue...)
+		// ivid must be 2 bytes length
+		tibitData.Data = append(tibitData.Data, iVidValue...)
+
+		bytes := []byte{
+			0xd7, 0x05, 0x01, 0x04, 0x03, 0x07, 0x08, 0x00,
+			0xd7, 0x05, 0x01, 0x01, 0x00, 0xd9, 0x05, 0x02,
+			0x80, 0x00,
+		}
+
+		tibitData.Data = append(tibitData.Data, bytes...)
+
+		return tibitData
+
+	default:
+		return &TibitFrame{
+			Data: []byte{},
+		}
+	}
+}
diff --git a/internal/pkg/core/l2oam/onu_msg_set_vlan_tag_filter.go b/internal/pkg/core/l2oam/onu_msg_set_vlan_tag_filter.go
new file mode 100644
index 0000000..980f444
--- /dev/null
+++ b/internal/pkg/core/l2oam/onu_msg_set_vlan_tag_filter.go
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package l2oam
+
+import (
+	"github.com/google/gopacket"
+)
+
+// GenerateSetVlanTagFilter generates VlanTagFilter message
+func GenerateSetVlanTagFilter(pkgType string, idx int, value []byte) gopacket.SerializableLayer {
+
+	if pkgType == OnuPkgTypeB {
+		switch idx {
+		case 1:
+			tibitData := &TibitFrame{
+				Data: []byte{
+					0x03, 0x00, 0x50, 0xfe, 0x90, 0x82, 0x60, 0x03,
+					0xca, 0xfe, 0x00, 0xb7, 0x00, 0x13, 0x03, 0x03,
+				}, //,0x81,0x00
+			}
+
+			tibitData.Data = append(tibitData.Data, value...)
+
+			return tibitData
+		case 2:
+			return &TibitFrame{
+				Data: []byte{
+					0x03, 0x00, 0x50, 0xfe, 0x90, 0x82, 0x60, 0x03,
+					0xca, 0xfe, 0x00, 0xb7, 0x00, 0x14, 0x03, 0x01,
+					0x00, 0x64,
+				},
+			}
+		default:
+			return &TibitFrame{
+				Data: []byte{},
+			}
+		}
+	} else {
+		switch idx {
+		case 1:
+			return &TibitFrame{
+				Data: []byte{
+					0x03, 0x00, 0x50, 0xFE, 0x00, 0x10, 0x00, 0x03,
+					0xD6, 0x00, 0x00, 0xD7, 0x05, 0x03, 0x03, 0x81,
+					0x00, 0x01,
+				},
+			}
+		case 2:
+			return &TibitFrame{
+				Data: []byte{
+					0x03, 0x00, 0x50, 0xFE, 0x00, 0x10, 0x00, 0x03,
+					0xD6, 0x00, 0x00, 0xD7, 0x05, 0x04, 0x03, 0x88,
+					0xa8, 0x00,
+				},
+			}
+		default:
+			return &TibitFrame{
+				Data: []byte{},
+			}
+		}
+	}
+}