mirror of https://github.com/vishvananda/netlink
249 lines
7.0 KiB
Go
249 lines
7.0 KiB
Go
package netlink
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"strings"
|
|
"syscall"
|
|
|
|
"github.com/vishvananda/netlink/nl"
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
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
|
|
}
|
|
|
|
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
|
// or incomplete.
|
|
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), unix.NLM_F_DUMP)
|
|
req.AddData(msg)
|
|
msgs, executeErr := req.Execute(unix.NETLINK_GENERIC, 0)
|
|
if executeErr != nil && !errors.Is(err, ErrDumpInterrupted) {
|
|
return nil, executeErr
|
|
}
|
|
pdps, err := parsePDP(msgs)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return pdps, executeErr
|
|
}
|
|
|
|
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
|
// or incomplete.
|
|
func GTPPDPList() ([]*PDP, error) {
|
|
return pkgHandle.GTPPDPList()
|
|
}
|
|
|
|
func gtpPDPGet(req *nl.NetlinkRequest) (*PDP, error) {
|
|
msgs, err := req.Execute(unix.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), unix.NLM_F_EXCL|unix.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(unix.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), unix.NLM_F_EXCL|unix.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(unix.NETLINK_GENERIC, 0)
|
|
return err
|
|
}
|
|
|
|
func GTPPDPDel(link Link, pdp *PDP) error {
|
|
return pkgHandle.GTPPDPDel(link, pdp)
|
|
}
|