blob: b826292e9fc739e734e8b0c057562f9da479a38d [file] [log] [blame]
Takahiro Suzukid7bf8202020-12-17 20:21:59 +09001/*
2 * Copyright 2020-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package l2oam
18
19import (
20 "encoding/binary"
21 "encoding/hex"
22 "fmt"
23
24 "github.com/google/gopacket"
25 "github.com/google/gopacket/layers"
26)
27
28// L2switchingDomainRequest is a structure for a request of "L2 Switching Domain/Action Inlet entry" message
29type L2switchingDomainRequest struct {
30 layers.BaseLayer
31 Opcode uint8
32 Flags uint16
33 OAMPDUCode uint8
34 OUId []byte // Organizationally Unique Identifier: 2a:ea:15 (Tibit Communications)
35 TOMIOpcode uint8
36 CTBranch uint8
37 CTType uint16
38 CTLength uint8
39 CTInstance uint32
40 OCBranch uint8
41 OCType uint16
42 OCLength uint8
43 OCInstance uint32
44 VcBranch uint8
45 VcLeaf uint16
46 VcLength uint8
47 SOLength uint8
48 SOBranch uint8
49 SOType uint16
50 SOValLength uint8
51 SOInstance uint8
52 TMLLength uint8
53 TMLList []TpidVid
54 TOPopLength uint8
55 TOPopValue uint8
56 TOSLength uint8
57 TOSList []TpidVid
58 TOPushLength uint8
59 TOPushList []TpidVid
60 EndBranch uint8
61 SizeMargin uint8
62}
63
64// TpidVid is a structure for TPID/VID set
65type TpidVid struct {
66 Length uint8
67 TpIDLength uint8
68 TpIDValue []byte
69 VIdLength uint8
70 VIdValue []byte
71}
72
73// String returns the string expression of L2switchingDomainRequest
74func (d *L2switchingDomainRequest) String() string {
75 message := fmt.Sprintf("Opcode:%x, Flags:%x, OAMPDUCode:%x, OUId:%v", d.Opcode, d.Flags, d.OAMPDUCode, hex.EncodeToString(d.OUId))
76 message = fmt.Sprintf("%s, TOMIOpcode:%x", message, d.TOMIOpcode)
77 message = fmt.Sprintf("%s, CTBranch:%x, CTType:%x, CTLength:%x, CTInstance:%x", message, d.CTBranch, d.CTType, d.CTLength, d.CTInstance)
78 message = fmt.Sprintf("%s, OCBranch:%x, OCType:%x, OCLength:%x, OCInstance:%x", message, d.OCBranch, d.OCType, d.OCLength, d.OCInstance)
79 message = fmt.Sprintf("%s, VcBranch:%x, VcLeaf:%x, VcLength:%x", message, d.VcBranch, d.VcLeaf, d.VcLength)
80 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)
81 message = fmt.Sprintf("%s, TMLLength:%x", message, d.TMLLength)
82 for i, tagMatch := range d.TMLList {
83 message = fmt.Sprintf("%s, %s", message, stringToTpidVid(&tagMatch, i))
84 }
85 message = fmt.Sprintf("%s, TOPopLength:%x, TOPopValue:%x", message, d.TOPopLength, d.TOPopValue)
86 message = fmt.Sprintf("%s, TOSLength:%x", message, d.TOSLength)
87 for i, tagOpSet := range d.TOSList {
88 message = fmt.Sprintf("%s, %s", message, stringToTpidVid(&tagOpSet, i))
89 }
90 message = fmt.Sprintf("%s, TOPushLength:%x", message, d.TOPushLength)
91 for i, tagOpPush := range d.TOPushList {
92 message = fmt.Sprintf("%s, %s", message, stringToTpidVid(&tagOpPush, i))
93 }
94 return message
95}
96
97func stringToTpidVid(tpidVid *TpidVid, index int) string {
98 message := fmt.Sprintf("EC[%v]:{Length:%x, TpIdLength:%x", index, tpidVid.Length, tpidVid.TpIDLength)
99 if tpidVid.TpIDLength != 128 {
100 message = fmt.Sprintf("%s, TpIdValue:%v", message, hex.EncodeToString(tpidVid.TpIDValue))
101 }
102 message = fmt.Sprintf("%s, VIdLength:%x", message, tpidVid.VIdLength)
103 if tpidVid.VIdLength != 128 {
104 message = fmt.Sprintf("%s, VIdValue:%v", message, hex.EncodeToString(tpidVid.VIdValue))
105 }
106 message = fmt.Sprintf("%s}", message)
107 return message
108}
109
110// Len returns the length of L2switchingDomainRequest
111func (d *L2switchingDomainRequest) Len() int {
112 return 22 + int(d.CTLength) + int(d.OCLength) + int(d.VcLength) + int(d.SizeMargin)
113}
114
115// LayerType returns the ethernet type of L2switchingDomainRequest
116func (d *L2switchingDomainRequest) LayerType() gopacket.LayerType { return layers.LayerTypeEthernet }
117
118// SerializeTo serializes a data structure to byte arrays
119func (d *L2switchingDomainRequest) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
120 plen := int(d.Len())
121 data, err := b.PrependBytes(plen)
122 if err != nil {
123 return err
124 }
125
126 i := 0
127 data[i] = byte(d.Opcode)
128 i++
129 binary.BigEndian.PutUint16(data[i:i+2], d.Flags)
130 i += 2
131 data[i] = byte(d.OAMPDUCode)
132 i++
133 copy(data[i:i+len(d.OUId)], d.OUId)
134 i += len(d.OUId)
135 data[i] = byte(d.TOMIOpcode)
136 i++
137 data[i] = byte(d.CTBranch)
138 i++
139 binary.BigEndian.PutUint16(data[i:i+2], d.CTType)
140 i += 2
141 data[i] = byte(d.CTLength)
142 i++
143 binary.BigEndian.PutUint32(data[i:i+4], d.CTInstance)
144 i += 4
145 data[i] = byte(d.OCBranch)
146 i++
147 binary.BigEndian.PutUint16(data[i:i+2], d.OCType)
148 i += 2
149 data[i] = byte(d.OCLength)
150 i++
151 binary.BigEndian.PutUint32(data[i:i+4], d.OCInstance)
152 i += 4
153 data[i] = byte(d.VcBranch)
154 i++
155 binary.BigEndian.PutUint16(data[i:i+2], d.VcLeaf)
156 i += 2
157 data[i] = byte(d.VcLength)
158 i++
159 data[i] = byte(d.SOLength)
160 i++
161 data[i] = byte(d.SOBranch)
162 i++
163 binary.BigEndian.PutUint16(data[i:i+2], d.SOType)
164 i += 2
165 data[i] = byte(d.SOValLength)
166 i++
167 data[i] = byte(d.SOInstance)
168 i++
169 data[i] = byte(d.TMLLength)
170 i++
171 for _, tagMatch := range d.TMLList {
172 nextIndex := serializeTpidVid(&tagMatch, data, i)
173 i = nextIndex
174 }
175 data[i] = byte(d.TOPopLength)
176 i++
177 data[i] = byte(d.TOPopValue)
178 i++
179 data[i] = byte(d.TOSLength)
180 i++
181 for _, tagOpSet := range d.TOSList {
182 nextIndex := serializeTpidVid(&tagOpSet, data, i)
183 i = nextIndex
184 }
185 data[i] = d.TOPushLength
186 i++
187 for _, tagOpPush := range d.TOPushList {
188 nextIndex := serializeTpidVid(&tagOpPush, data, i)
189 i = nextIndex
190 }
191 data[i] = byte(d.EndBranch)
192
193 return nil
194}
195
196func serializeTpidVid(tpidVid *TpidVid, data []byte, startIndex int) int {
197 i := startIndex
198 data[i] = tpidVid.Length
199 i++
200 ln := tpidVid.TpIDLength
201 data[i] = ln
202 i++
203 if ln != 128 { // !Empty?
204 copy(data[i:i+int(ln)], tpidVid.TpIDValue)
205 i += int(ln)
206 }
207 ln = tpidVid.VIdLength
208 data[i] = ln
209 i++
210 if ln != 128 { // !Empty?
211 copy(data[i:i+int(ln)], tpidVid.VIdValue)
212 i += int(ln)
213 }
214 return i
215}