1 // Copyright (c) 2017 Cisco and/or its affiliates.
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at:
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
23 "github.com/lunixbochs/struc"
25 "git.fd.io/govpp.git/api"
28 // MsgCodec provides encoding and decoding functionality of `api.Message` structs into/from
29 // binary format as accepted by VPP.
30 type MsgCodec struct{}
32 // VppRequestHeader struct contains header fields implemented by all VPP requests.
33 type VppRequestHeader struct {
39 // VppReplyHeader struct contains header fields implemented by all VPP replies.
40 type VppReplyHeader struct {
45 // VppEventHeader struct contains header fields implemented by all VPP events.
46 type VppEventHeader struct {
51 // VppOtherHeader struct contains header fields implemented by other VPP messages (not requests nor replies).
52 type VppOtherHeader struct {
56 // EncodeMsg encodes provided `Message` structure into its binary-encoded data representation.
57 func (*MsgCodec) EncodeMsg(msg api.Message, msgID uint16) (data []byte, err error) {
59 return nil, errors.New("nil message passed in")
62 // try to recover panic which might possibly occur in struc.Pack call
64 if r := recover(); r != nil {
66 if err, ok = r.(error); !ok {
67 err = fmt.Errorf("%v", r)
69 err = fmt.Errorf("panic occurred during encoding message %s: %v", msg.GetMessageName(), err)
73 var header interface{}
75 // encode message header
76 switch msg.GetMessageType() {
77 case api.RequestMessage:
78 header = &VppRequestHeader{VlMsgID: msgID}
79 case api.ReplyMessage:
80 header = &VppReplyHeader{VlMsgID: msgID}
81 case api.EventMessage:
82 header = &VppEventHeader{VlMsgID: msgID}
84 header = &VppOtherHeader{VlMsgID: msgID}
87 buf := new(bytes.Buffer)
89 // encode message header
90 if err := struc.Pack(buf, header); err != nil {
91 return nil, fmt.Errorf("failed to encode message header: %+v, error: %v", header, err)
94 // encode message content
95 if reflect.TypeOf(msg).Elem().NumField() > 0 {
96 if err := struc.Pack(buf, msg); err != nil {
97 return nil, fmt.Errorf("failed to encode message data: %+v, error: %v", data, err)
101 return buf.Bytes(), nil
104 // DecodeMsg decodes binary-encoded data of a message into provided `Message` structure.
105 func (*MsgCodec) DecodeMsg(data []byte, msg api.Message) (err error) {
107 return errors.New("nil message passed in")
110 // try to recover panic which might possibly occur
112 if r := recover(); r != nil {
114 if err, ok = r.(error); !ok {
115 err = fmt.Errorf("%v", r)
117 err = fmt.Errorf("panic occurred during decoding message %s: %v", msg.GetMessageName(), err)
121 var header interface{}
123 // check which header is expected
124 switch msg.GetMessageType() {
125 case api.RequestMessage:
126 header = new(VppRequestHeader)
127 case api.ReplyMessage:
128 header = new(VppReplyHeader)
129 case api.EventMessage:
130 header = new(VppEventHeader)
132 header = new(VppOtherHeader)
135 buf := bytes.NewReader(data)
137 // decode message header
138 if err = struc.Unpack(buf, header); err != nil {
139 return fmt.Errorf("failed to decode message header: %+v, error: %v", header, err)
142 // decode message content
143 if err := struc.Unpack(buf, msg); err != nil {
144 return fmt.Errorf("failed to decode message data: %+v, error: %v", data, err)
150 func (*MsgCodec) DecodeMsgContext(data []byte, msg api.Message) (uint32, error) {
152 return 0, errors.New("nil message passed in")
155 var header interface{}
156 var getContext func() uint32
158 // check which header is expected
159 switch msg.GetMessageType() {
160 case api.RequestMessage:
161 header = new(VppRequestHeader)
162 getContext = func() uint32 { return header.(*VppRequestHeader).Context }
164 case api.ReplyMessage:
165 header = new(VppReplyHeader)
166 getContext = func() uint32 { return header.(*VppReplyHeader).Context }
172 buf := bytes.NewReader(data)
174 // decode message header
175 if err := struc.Unpack(buf, header); err != nil {
176 return 0, fmt.Errorf("decoding message header failed: %v", err)
179 return getContext(), nil