mirror of https://github.com/vishvananda/netlink
Add support for GPRS Tunnelling Protocol(GTP)
Signed-off-by: Wataru Ishida <ishida.wataru@lab.ntt.co.jp>
This commit is contained in:
parent
fe2e32c2fb
commit
58c32ae2d7
|
@ -0,0 +1,238 @@
|
||||||
|
package netlink
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/vishvananda/netlink/nl"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PDP struct {
|
||||||
|
Version uint32
|
||||||
|
TID uint64
|
||||||
|
PeerAddress net.IP
|
||||||
|
MSAddress net.IP
|
||||||
|
Flow uint16
|
||||||
|
NetNSFD uint32
|
||||||
|
ITEI uint32
|
||||||
|
OTEI uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pdp *PDP) String() string {
|
||||||
|
elems := []string{}
|
||||||
|
elems = append(elems, fmt.Sprintf("Version: %d", pdp.Version))
|
||||||
|
if pdp.Version == 0 {
|
||||||
|
elems = append(elems, fmt.Sprintf("TID: %d", pdp.TID))
|
||||||
|
} else if pdp.Version == 1 {
|
||||||
|
elems = append(elems, fmt.Sprintf("TEI: %d/%d", pdp.ITEI, pdp.OTEI))
|
||||||
|
}
|
||||||
|
elems = append(elems, fmt.Sprintf("MS-Address: %s", pdp.MSAddress))
|
||||||
|
elems = append(elems, fmt.Sprintf("Peer-Address: %s", pdp.PeerAddress))
|
||||||
|
return fmt.Sprintf("{%s}", strings.Join(elems, " "))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PDP) parseAttributes(attrs []syscall.NetlinkRouteAttr) error {
|
||||||
|
for _, a := range attrs {
|
||||||
|
switch a.Attr.Type {
|
||||||
|
case nl.GENL_GTP_ATTR_VERSION:
|
||||||
|
p.Version = native.Uint32(a.Value)
|
||||||
|
case nl.GENL_GTP_ATTR_TID:
|
||||||
|
p.TID = native.Uint64(a.Value)
|
||||||
|
case nl.GENL_GTP_ATTR_PEER_ADDRESS:
|
||||||
|
p.PeerAddress = net.IP(a.Value)
|
||||||
|
case nl.GENL_GTP_ATTR_MS_ADDRESS:
|
||||||
|
p.MSAddress = net.IP(a.Value)
|
||||||
|
case nl.GENL_GTP_ATTR_FLOW:
|
||||||
|
p.Flow = native.Uint16(a.Value)
|
||||||
|
case nl.GENL_GTP_ATTR_NET_NS_FD:
|
||||||
|
p.NetNSFD = native.Uint32(a.Value)
|
||||||
|
case nl.GENL_GTP_ATTR_I_TEI:
|
||||||
|
p.ITEI = native.Uint32(a.Value)
|
||||||
|
case nl.GENL_GTP_ATTR_O_TEI:
|
||||||
|
p.OTEI = native.Uint32(a.Value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parsePDP(msgs [][]byte) ([]*PDP, error) {
|
||||||
|
pdps := make([]*PDP, 0, len(msgs))
|
||||||
|
for _, m := range msgs {
|
||||||
|
attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
pdp := &PDP{}
|
||||||
|
if err := pdp.parseAttributes(attrs); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
pdps = append(pdps, pdp)
|
||||||
|
}
|
||||||
|
return pdps, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handle) GTPPDPList() ([]*PDP, error) {
|
||||||
|
f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
msg := &nl.Genlmsg{
|
||||||
|
Command: nl.GENL_GTP_CMD_GETPDP,
|
||||||
|
Version: nl.GENL_GTP_VERSION,
|
||||||
|
}
|
||||||
|
req := h.newNetlinkRequest(int(f.ID), syscall.NLM_F_DUMP)
|
||||||
|
req.AddData(msg)
|
||||||
|
msgs, err := req.Execute(syscall.NETLINK_GENERIC, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return parsePDP(msgs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GTPPDPList() ([]*PDP, error) {
|
||||||
|
return pkgHandle.GTPPDPList()
|
||||||
|
}
|
||||||
|
|
||||||
|
func gtpPDPGet(req *nl.NetlinkRequest) (*PDP, error) {
|
||||||
|
msgs, err := req.Execute(syscall.NETLINK_GENERIC, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
pdps, err := parsePDP(msgs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(pdps) != 1 {
|
||||||
|
return nil, fmt.Errorf("invalid reqponse for GENL_GTP_CMD_GETPDP")
|
||||||
|
}
|
||||||
|
return pdps[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handle) GTPPDPByTID(link Link, tid int) (*PDP, error) {
|
||||||
|
f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
msg := &nl.Genlmsg{
|
||||||
|
Command: nl.GENL_GTP_CMD_GETPDP,
|
||||||
|
Version: nl.GENL_GTP_VERSION,
|
||||||
|
}
|
||||||
|
req := h.newNetlinkRequest(int(f.ID), 0)
|
||||||
|
req.AddData(msg)
|
||||||
|
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(0)))
|
||||||
|
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index))))
|
||||||
|
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_TID, nl.Uint64Attr(uint64(tid))))
|
||||||
|
return gtpPDPGet(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GTPPDPByTID(link Link, tid int) (*PDP, error) {
|
||||||
|
return pkgHandle.GTPPDPByTID(link, tid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handle) GTPPDPByITEI(link Link, itei int) (*PDP, error) {
|
||||||
|
f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
msg := &nl.Genlmsg{
|
||||||
|
Command: nl.GENL_GTP_CMD_GETPDP,
|
||||||
|
Version: nl.GENL_GTP_VERSION,
|
||||||
|
}
|
||||||
|
req := h.newNetlinkRequest(int(f.ID), 0)
|
||||||
|
req.AddData(msg)
|
||||||
|
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(1)))
|
||||||
|
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index))))
|
||||||
|
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_I_TEI, nl.Uint32Attr(uint32(itei))))
|
||||||
|
return gtpPDPGet(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GTPPDPByITEI(link Link, itei int) (*PDP, error) {
|
||||||
|
return pkgHandle.GTPPDPByITEI(link, itei)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handle) GTPPDPByMSAddress(link Link, addr net.IP) (*PDP, error) {
|
||||||
|
f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
msg := &nl.Genlmsg{
|
||||||
|
Command: nl.GENL_GTP_CMD_GETPDP,
|
||||||
|
Version: nl.GENL_GTP_VERSION,
|
||||||
|
}
|
||||||
|
req := h.newNetlinkRequest(int(f.ID), 0)
|
||||||
|
req.AddData(msg)
|
||||||
|
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(0)))
|
||||||
|
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index))))
|
||||||
|
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_MS_ADDRESS, []byte(addr.To4())))
|
||||||
|
return gtpPDPGet(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GTPPDPByMSAddress(link Link, addr net.IP) (*PDP, error) {
|
||||||
|
return pkgHandle.GTPPDPByMSAddress(link, addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handle) GTPPDPAdd(link Link, pdp *PDP) error {
|
||||||
|
f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
msg := &nl.Genlmsg{
|
||||||
|
Command: nl.GENL_GTP_CMD_NEWPDP,
|
||||||
|
Version: nl.GENL_GTP_VERSION,
|
||||||
|
}
|
||||||
|
req := h.newNetlinkRequest(int(f.ID), syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
|
||||||
|
req.AddData(msg)
|
||||||
|
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(pdp.Version)))
|
||||||
|
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index))))
|
||||||
|
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_PEER_ADDRESS, []byte(pdp.PeerAddress.To4())))
|
||||||
|
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_MS_ADDRESS, []byte(pdp.MSAddress.To4())))
|
||||||
|
|
||||||
|
switch pdp.Version {
|
||||||
|
case 0:
|
||||||
|
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_TID, nl.Uint64Attr(pdp.TID)))
|
||||||
|
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_FLOW, nl.Uint16Attr(pdp.Flow)))
|
||||||
|
case 1:
|
||||||
|
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_I_TEI, nl.Uint32Attr(pdp.ITEI)))
|
||||||
|
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_O_TEI, nl.Uint32Attr(pdp.OTEI)))
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupported GTP version: %d", pdp.Version)
|
||||||
|
}
|
||||||
|
_, err = req.Execute(syscall.NETLINK_GENERIC, 0)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func GTPPDPAdd(link Link, pdp *PDP) error {
|
||||||
|
return pkgHandle.GTPPDPAdd(link, pdp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handle) GTPPDPDel(link Link, pdp *PDP) error {
|
||||||
|
f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
msg := &nl.Genlmsg{
|
||||||
|
Command: nl.GENL_GTP_CMD_DELPDP,
|
||||||
|
Version: nl.GENL_GTP_VERSION,
|
||||||
|
}
|
||||||
|
req := h.newNetlinkRequest(int(f.ID), syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
|
||||||
|
req.AddData(msg)
|
||||||
|
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(pdp.Version)))
|
||||||
|
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index))))
|
||||||
|
|
||||||
|
switch pdp.Version {
|
||||||
|
case 0:
|
||||||
|
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_TID, nl.Uint64Attr(pdp.TID)))
|
||||||
|
case 1:
|
||||||
|
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_I_TEI, nl.Uint32Attr(pdp.ITEI)))
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupported GTP version: %d", pdp.Version)
|
||||||
|
}
|
||||||
|
_, err = req.Execute(syscall.NETLINK_GENERIC, 0)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func GTPPDPDel(link Link, pdp *PDP) error {
|
||||||
|
return pkgHandle.GTPPDPDel(link, pdp)
|
||||||
|
}
|
|
@ -0,0 +1,116 @@
|
||||||
|
// +build linux
|
||||||
|
|
||||||
|
package netlink
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPDPv0AddDel(t *testing.T) {
|
||||||
|
tearDown := setUpNetlinkTestWithKModule(t, "gtp")
|
||||||
|
defer tearDown()
|
||||||
|
|
||||||
|
if err := LinkAdd(testGTPLink(t)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
link, err := LinkByName("gtp0")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = GTPPDPAdd(link, &PDP{
|
||||||
|
PeerAddress: net.ParseIP("1.1.1.1"),
|
||||||
|
MSAddress: net.ParseIP("2.2.2.2"),
|
||||||
|
TID: 10,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
list, err := GTPPDPList()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(list) != 1 {
|
||||||
|
t.Fatal("Failed to add v0 PDP")
|
||||||
|
}
|
||||||
|
pdp, err := GTPPDPByMSAddress(link, net.ParseIP("2.2.2.2"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if pdp == nil {
|
||||||
|
t.Fatal("failed to get v0 PDP by MS address")
|
||||||
|
}
|
||||||
|
pdp, err = GTPPDPByTID(link, 10)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if pdp == nil {
|
||||||
|
t.Fatal("failed to get v0 PDP by TID")
|
||||||
|
}
|
||||||
|
err = GTPPDPDel(link, &PDP{TID: 10})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
list, err = GTPPDPList()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(list) != 0 {
|
||||||
|
t.Fatal("Failed to delete v0 PDP")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPDPv1AddDel(t *testing.T) {
|
||||||
|
tearDown := setUpNetlinkTestWithKModule(t, "gtp")
|
||||||
|
defer tearDown()
|
||||||
|
|
||||||
|
if err := LinkAdd(testGTPLink(t)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
link, err := LinkByName("gtp0")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = GTPPDPAdd(link, &PDP{
|
||||||
|
PeerAddress: net.ParseIP("1.1.1.1"),
|
||||||
|
MSAddress: net.ParseIP("2.2.2.2"),
|
||||||
|
Version: 1,
|
||||||
|
ITEI: 10,
|
||||||
|
OTEI: 10,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
list, err := GTPPDPList()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(list) != 1 {
|
||||||
|
t.Fatal("Failed to add v1 PDP")
|
||||||
|
}
|
||||||
|
pdp, err := GTPPDPByMSAddress(link, net.ParseIP("2.2.2.2"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if pdp == nil {
|
||||||
|
t.Fatal("failed to get v1 PDP by MS address")
|
||||||
|
}
|
||||||
|
pdp, err = GTPPDPByITEI(link, 10)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if pdp == nil {
|
||||||
|
t.Fatal("failed to get v1 PDP by ITEI")
|
||||||
|
}
|
||||||
|
err = GTPPDPDel(link, &PDP{Version: 1, ITEI: 10})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
list, err = GTPPDPList()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(list) != 0 {
|
||||||
|
t.Fatal("Failed to delete v1 PDP")
|
||||||
|
}
|
||||||
|
}
|
16
link.go
16
link.go
|
@ -734,6 +734,22 @@ func (vrf *Vrf) Type() string {
|
||||||
return "vrf"
|
return "vrf"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GTP struct {
|
||||||
|
LinkAttrs
|
||||||
|
FD0 int
|
||||||
|
FD1 int
|
||||||
|
Role int
|
||||||
|
PDPHashsize int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gtp *GTP) Attrs() *LinkAttrs {
|
||||||
|
return >p.LinkAttrs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gtp *GTP) Type() string {
|
||||||
|
return "gtp"
|
||||||
|
}
|
||||||
|
|
||||||
// iproute2 supported devices;
|
// iproute2 supported devices;
|
||||||
// vlan | veth | vcan | dummy | ifb | macvlan | macvtap |
|
// vlan | veth | vcan | dummy | ifb | macvlan | macvtap |
|
||||||
// bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan |
|
// bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan |
|
||||||
|
|
|
@ -846,6 +846,8 @@ func (h *Handle) linkModify(link Link, flags int) error {
|
||||||
addVrfAttrs(vrf, linkInfo)
|
addVrfAttrs(vrf, linkInfo)
|
||||||
} else if bridge, ok := link.(*Bridge); ok {
|
} else if bridge, ok := link.(*Bridge); ok {
|
||||||
addBridgeAttrs(bridge, linkInfo)
|
addBridgeAttrs(bridge, linkInfo)
|
||||||
|
} else if gtp, ok := link.(*GTP); ok {
|
||||||
|
addGTPAttrs(gtp, linkInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
req.AddData(linkInfo)
|
req.AddData(linkInfo)
|
||||||
|
@ -1079,6 +1081,8 @@ func LinkDeserialize(hdr *syscall.NlMsghdr, m []byte) (Link, error) {
|
||||||
link = &Vti{}
|
link = &Vti{}
|
||||||
case "vrf":
|
case "vrf":
|
||||||
link = &Vrf{}
|
link = &Vrf{}
|
||||||
|
case "gtp":
|
||||||
|
link = >P{}
|
||||||
default:
|
default:
|
||||||
link = &GenericLink{LinkType: linkType}
|
link = &GenericLink{LinkType: linkType}
|
||||||
}
|
}
|
||||||
|
@ -1110,6 +1114,8 @@ func LinkDeserialize(hdr *syscall.NlMsghdr, m []byte) (Link, error) {
|
||||||
parseVrfData(link, data)
|
parseVrfData(link, data)
|
||||||
case "bridge":
|
case "bridge":
|
||||||
parseBridgeData(link, data)
|
parseBridgeData(link, data)
|
||||||
|
case "gtp":
|
||||||
|
parseGTPData(link, data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1740,3 +1746,29 @@ func parseBridgeData(bridge Link, data []syscall.NetlinkRouteAttr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func addGTPAttrs(gtp *GTP, linkInfo *nl.RtAttr) {
|
||||||
|
data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
|
||||||
|
nl.NewRtAttrChild(data, nl.IFLA_GTP_FD0, nl.Uint32Attr(uint32(gtp.FD0)))
|
||||||
|
nl.NewRtAttrChild(data, nl.IFLA_GTP_FD1, nl.Uint32Attr(uint32(gtp.FD1)))
|
||||||
|
nl.NewRtAttrChild(data, nl.IFLA_GTP_PDP_HASHSIZE, nl.Uint32Attr(131072))
|
||||||
|
if gtp.Role != nl.GTP_ROLE_GGSN {
|
||||||
|
nl.NewRtAttrChild(data, nl.IFLA_GTP_ROLE, nl.Uint32Attr(uint32(gtp.Role)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseGTPData(link Link, data []syscall.NetlinkRouteAttr) {
|
||||||
|
gtp := link.(*GTP)
|
||||||
|
for _, datum := range data {
|
||||||
|
switch datum.Attr.Type {
|
||||||
|
case nl.IFLA_GTP_FD0:
|
||||||
|
gtp.FD0 = int(native.Uint32(datum.Value))
|
||||||
|
case nl.IFLA_GTP_FD1:
|
||||||
|
gtp.FD1 = int(native.Uint32(datum.Value))
|
||||||
|
case nl.IFLA_GTP_PDP_HASHSIZE:
|
||||||
|
gtp.PDPHashsize = int(native.Uint32(datum.Value))
|
||||||
|
case nl.IFLA_GTP_ROLE:
|
||||||
|
gtp.Role = int(native.Uint32(datum.Value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
33
link_test.go
33
link_test.go
|
@ -1247,3 +1247,36 @@ func TestLinkSubscribeWithProtinfo(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testGTPLink(t *testing.T) *GTP {
|
||||||
|
conn1, err := net.ListenUDP("udp", &net.UDPAddr{
|
||||||
|
IP: net.ParseIP("0.0.0.0"),
|
||||||
|
Port: 3386,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
conn2, err := net.ListenUDP("udp", &net.UDPAddr{
|
||||||
|
IP: net.ParseIP("0.0.0.0"),
|
||||||
|
Port: 2152,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
fd1, _ := conn1.File()
|
||||||
|
fd2, _ := conn2.File()
|
||||||
|
return >P{
|
||||||
|
LinkAttrs: LinkAttrs{
|
||||||
|
Name: "gtp0",
|
||||||
|
},
|
||||||
|
FD0: int(fd1.Fd()),
|
||||||
|
FD1: int(fd2.Fd()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLinkAddDelGTP(t *testing.T) {
|
||||||
|
tearDown := setUpNetlinkTestWithKModule(t, "gtp")
|
||||||
|
defer tearDown()
|
||||||
|
gtp := testGTPLink(t)
|
||||||
|
testLinkAddDel(t, gtp)
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
package netlink
|
package netlink
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/vishvananda/netns"
|
"github.com/vishvananda/netns"
|
||||||
|
@ -56,3 +59,25 @@ func setUpMPLSNetlinkTest(t *testing.T) tearDownNetlinkTest {
|
||||||
setUpF("/proc/sys/net/mpls/conf/lo/input", "1")
|
setUpF("/proc/sys/net/mpls/conf/lo/input", "1")
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setUpNetlinkTestWithKModule(t *testing.T, name string) tearDownNetlinkTest {
|
||||||
|
file, err := ioutil.ReadFile("/proc/modules")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Failed to open /proc/modules", err)
|
||||||
|
}
|
||||||
|
found := false
|
||||||
|
for _, line := range strings.Split(string(file), "\n") {
|
||||||
|
n := strings.Split(line, " ")[0]
|
||||||
|
if n == name {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
msg := fmt.Sprintf("Skipped test because it requres kmodule %s.", name)
|
||||||
|
log.Println(msg)
|
||||||
|
t.Skip(msg)
|
||||||
|
}
|
||||||
|
return setUpNetlinkTest(t)
|
||||||
|
}
|
||||||
|
|
|
@ -46,6 +46,31 @@ const (
|
||||||
GENL_CTRL_ATTR_MCAST_GRP_ID
|
GENL_CTRL_ATTR_MCAST_GRP_ID
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
GENL_GTP_VERSION = 0
|
||||||
|
GENL_GTP_NAME = "gtp"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
GENL_GTP_CMD_NEWPDP = iota
|
||||||
|
GENL_GTP_CMD_DELPDP
|
||||||
|
GENL_GTP_CMD_GETPDP
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
GENL_GTP_ATTR_UNSPEC = iota
|
||||||
|
GENL_GTP_ATTR_LINK
|
||||||
|
GENL_GTP_ATTR_VERSION
|
||||||
|
GENL_GTP_ATTR_TID
|
||||||
|
GENL_GTP_ATTR_PEER_ADDRESS
|
||||||
|
GENL_GTP_ATTR_MS_ADDRESS
|
||||||
|
GENL_GTP_ATTR_FLOW
|
||||||
|
GENL_GTP_ATTR_NET_NS_FD
|
||||||
|
GENL_GTP_ATTR_I_TEI
|
||||||
|
GENL_GTP_ATTR_O_TEI
|
||||||
|
GENL_GTP_ATTR_PAD
|
||||||
|
)
|
||||||
|
|
||||||
type Genlmsg struct {
|
type Genlmsg struct {
|
||||||
Command uint8
|
Command uint8
|
||||||
Version uint8
|
Version uint8
|
||||||
|
|
|
@ -505,3 +505,16 @@ const (
|
||||||
IFLA_BR_MCAST_MLD_VERSION
|
IFLA_BR_MCAST_MLD_VERSION
|
||||||
IFLA_BR_MAX = IFLA_BR_MCAST_MLD_VERSION
|
IFLA_BR_MAX = IFLA_BR_MCAST_MLD_VERSION
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
IFLA_GTP_UNSPEC = iota
|
||||||
|
IFLA_GTP_FD0
|
||||||
|
IFLA_GTP_FD1
|
||||||
|
IFLA_GTP_PDP_HASHSIZE
|
||||||
|
IFLA_GTP_ROLE
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
GTP_ROLE_GGSN = iota
|
||||||
|
GTP_ROLE_SGSN
|
||||||
|
)
|
||||||
|
|
Loading…
Reference in New Issue