blob: 90186a80264e1de67a9673b24acd289002844b8d [file] [log] [blame]
/*
* Copyright 2018-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 packetHandlers
import (
"errors"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
)
func PushSingleTag(tag int, pkt gopacket.Packet, pbit uint8) (gopacket.Packet, error) {
// TODO can this method be semplified?
if eth := getEthernetLayer(pkt); eth != nil {
ethernetLayer := &layers.Ethernet{
SrcMAC: eth.SrcMAC,
DstMAC: eth.DstMAC,
EthernetType: 0x8100,
}
dot1qLayer := &layers.Dot1Q{
Type: eth.EthernetType,
VLANIdentifier: uint16(tag),
Priority: pbit,
}
buffer := gopacket.NewSerializeBuffer()
_ = gopacket.SerializeLayers(
buffer,
gopacket.SerializeOptions{
FixLengths: false,
},
ethernetLayer,
dot1qLayer,
gopacket.Payload(eth.Payload),
)
ret := gopacket.NewPacket(
buffer.Bytes(),
layers.LayerTypeEthernet,
gopacket.Default,
)
return ret, nil
}
return nil, errors.New("Couldn't extract LayerTypeEthernet from packet")
}
func PushDoubleTag(stag int, ctag int, pkt gopacket.Packet, pbit uint8) (gopacket.Packet, error) {
singleTaggedPkt, err := PushSingleTag(ctag, pkt, pbit)
if err != nil {
return nil, err
}
doubleTaggedPkt, err := PushSingleTag(stag, singleTaggedPkt, pbit)
if err != nil {
return nil, err
}
return doubleTaggedPkt, nil
}
func PopSingleTag(pkt gopacket.Packet) (gopacket.Packet, error) {
layer, err := getDot1QLayer(pkt)
if err != nil {
return nil, err
}
if eth := getEthernetLayer(pkt); eth != nil {
ethernetLayer := &layers.Ethernet{
SrcMAC: eth.SrcMAC,
DstMAC: eth.DstMAC,
EthernetType: layer.Type,
}
buffer := gopacket.NewSerializeBuffer()
_ = gopacket.SerializeLayers(buffer, gopacket.SerializeOptions{},
ethernetLayer,
gopacket.Payload(layer.Payload),
)
retpkt := gopacket.NewPacket(
buffer.Bytes(),
layers.LayerTypeEthernet,
gopacket.Default,
)
return retpkt, nil
}
return nil, errors.New("no-ethernet-layer")
}
func PopDoubleTag(pkt gopacket.Packet) (gopacket.Packet, error) {
packet, err := PopSingleTag(pkt)
if err != nil {
return nil, err
}
packet, err = PopSingleTag(packet)
if err != nil {
return nil, err
}
return packet, nil
}
func getEthernetLayer(pkt gopacket.Packet) *layers.Ethernet {
eth := &layers.Ethernet{}
if ethLayer := pkt.Layer(layers.LayerTypeEthernet); ethLayer != nil {
eth, _ = ethLayer.(*layers.Ethernet)
}
return eth
}
func getDot1QLayer(pkt gopacket.Packet) (*layers.Dot1Q, error) {
if dot1qLayer := pkt.Layer(layers.LayerTypeDot1Q); dot1qLayer != nil {
dot1q := dot1qLayer.(*layers.Dot1Q)
return dot1q, nil
}
return nil, errors.New("no-dot1q-layer-in-packet")
}
func GetVlanTag(pkt gopacket.Packet) (uint16, error) {
dot1q, err := getDot1QLayer(pkt)
if err != nil {
return 0, err
}
return dot1q.VLANIdentifier, nil
}
func GetPbit(pkt gopacket.Packet) (uint8, error) {
dot1q, err := getDot1QLayer(pkt)
if err != nil {
return 0, err
}
return dot1q.Priority, nil
}
// godet inner and outer tag from a packet
// TODO unit test
func GetTagsFromPacket(pkt gopacket.Packet) (uint16, uint16, error) {
sTag, err := GetVlanTag(pkt)
if err != nil {
return 0, 0, err
}
singleTagPkt, err := PopSingleTag(pkt)
if err != nil {
return 0, 0, err
}
cTag, err := GetVlanTag(singleTagPkt)
if err != nil {
return 0, 0, err
}
return sTag, cTag, nil
}