github.com/vishvananda/netlink@v1.3.1/gtp_linux.go (about) 1 package netlink 2 3 import ( 4 "errors" 5 "fmt" 6 "net" 7 "strings" 8 "syscall" 9 10 "github.com/vishvananda/netlink/nl" 11 "golang.org/x/sys/unix" 12 ) 13 14 type PDP struct { 15 Version uint32 16 TID uint64 17 PeerAddress net.IP 18 MSAddress net.IP 19 Flow uint16 20 NetNSFD uint32 21 ITEI uint32 22 OTEI uint32 23 } 24 25 func (pdp *PDP) String() string { 26 elems := []string{} 27 elems = append(elems, fmt.Sprintf("Version: %d", pdp.Version)) 28 if pdp.Version == 0 { 29 elems = append(elems, fmt.Sprintf("TID: %d", pdp.TID)) 30 } else if pdp.Version == 1 { 31 elems = append(elems, fmt.Sprintf("TEI: %d/%d", pdp.ITEI, pdp.OTEI)) 32 } 33 elems = append(elems, fmt.Sprintf("MS-Address: %s", pdp.MSAddress)) 34 elems = append(elems, fmt.Sprintf("Peer-Address: %s", pdp.PeerAddress)) 35 return fmt.Sprintf("{%s}", strings.Join(elems, " ")) 36 } 37 38 func (p *PDP) parseAttributes(attrs []syscall.NetlinkRouteAttr) error { 39 for _, a := range attrs { 40 switch a.Attr.Type { 41 case nl.GENL_GTP_ATTR_VERSION: 42 p.Version = native.Uint32(a.Value) 43 case nl.GENL_GTP_ATTR_TID: 44 p.TID = native.Uint64(a.Value) 45 case nl.GENL_GTP_ATTR_PEER_ADDRESS: 46 p.PeerAddress = net.IP(a.Value) 47 case nl.GENL_GTP_ATTR_MS_ADDRESS: 48 p.MSAddress = net.IP(a.Value) 49 case nl.GENL_GTP_ATTR_FLOW: 50 p.Flow = native.Uint16(a.Value) 51 case nl.GENL_GTP_ATTR_NET_NS_FD: 52 p.NetNSFD = native.Uint32(a.Value) 53 case nl.GENL_GTP_ATTR_I_TEI: 54 p.ITEI = native.Uint32(a.Value) 55 case nl.GENL_GTP_ATTR_O_TEI: 56 p.OTEI = native.Uint32(a.Value) 57 } 58 } 59 return nil 60 } 61 62 func parsePDP(msgs [][]byte) ([]*PDP, error) { 63 pdps := make([]*PDP, 0, len(msgs)) 64 for _, m := range msgs { 65 attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:]) 66 if err != nil { 67 return nil, err 68 } 69 pdp := &PDP{} 70 if err := pdp.parseAttributes(attrs); err != nil { 71 return nil, err 72 } 73 pdps = append(pdps, pdp) 74 } 75 return pdps, nil 76 } 77 78 // If the returned error is [ErrDumpInterrupted], results may be inconsistent 79 // or incomplete. 80 func (h *Handle) GTPPDPList() ([]*PDP, error) { 81 f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME) 82 if err != nil { 83 return nil, err 84 } 85 msg := &nl.Genlmsg{ 86 Command: nl.GENL_GTP_CMD_GETPDP, 87 Version: nl.GENL_GTP_VERSION, 88 } 89 req := h.newNetlinkRequest(int(f.ID), unix.NLM_F_DUMP) 90 req.AddData(msg) 91 msgs, executeErr := req.Execute(unix.NETLINK_GENERIC, 0) 92 if executeErr != nil && !errors.Is(err, ErrDumpInterrupted) { 93 return nil, executeErr 94 } 95 pdps, err := parsePDP(msgs) 96 if err != nil { 97 return nil, err 98 } 99 return pdps, executeErr 100 } 101 102 // If the returned error is [ErrDumpInterrupted], results may be inconsistent 103 // or incomplete. 104 func GTPPDPList() ([]*PDP, error) { 105 return pkgHandle.GTPPDPList() 106 } 107 108 func gtpPDPGet(req *nl.NetlinkRequest) (*PDP, error) { 109 msgs, err := req.Execute(unix.NETLINK_GENERIC, 0) 110 if err != nil { 111 return nil, err 112 } 113 pdps, err := parsePDP(msgs) 114 if err != nil { 115 return nil, err 116 } 117 if len(pdps) != 1 { 118 return nil, fmt.Errorf("invalid reqponse for GENL_GTP_CMD_GETPDP") 119 } 120 return pdps[0], nil 121 } 122 123 func (h *Handle) GTPPDPByTID(link Link, tid int) (*PDP, error) { 124 f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME) 125 if err != nil { 126 return nil, err 127 } 128 msg := &nl.Genlmsg{ 129 Command: nl.GENL_GTP_CMD_GETPDP, 130 Version: nl.GENL_GTP_VERSION, 131 } 132 req := h.newNetlinkRequest(int(f.ID), 0) 133 req.AddData(msg) 134 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(0))) 135 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index)))) 136 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_TID, nl.Uint64Attr(uint64(tid)))) 137 return gtpPDPGet(req) 138 } 139 140 func GTPPDPByTID(link Link, tid int) (*PDP, error) { 141 return pkgHandle.GTPPDPByTID(link, tid) 142 } 143 144 func (h *Handle) GTPPDPByITEI(link Link, itei int) (*PDP, error) { 145 f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME) 146 if err != nil { 147 return nil, err 148 } 149 msg := &nl.Genlmsg{ 150 Command: nl.GENL_GTP_CMD_GETPDP, 151 Version: nl.GENL_GTP_VERSION, 152 } 153 req := h.newNetlinkRequest(int(f.ID), 0) 154 req.AddData(msg) 155 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(1))) 156 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index)))) 157 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_I_TEI, nl.Uint32Attr(uint32(itei)))) 158 return gtpPDPGet(req) 159 } 160 161 func GTPPDPByITEI(link Link, itei int) (*PDP, error) { 162 return pkgHandle.GTPPDPByITEI(link, itei) 163 } 164 165 func (h *Handle) GTPPDPByMSAddress(link Link, addr net.IP) (*PDP, error) { 166 f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME) 167 if err != nil { 168 return nil, err 169 } 170 msg := &nl.Genlmsg{ 171 Command: nl.GENL_GTP_CMD_GETPDP, 172 Version: nl.GENL_GTP_VERSION, 173 } 174 req := h.newNetlinkRequest(int(f.ID), 0) 175 req.AddData(msg) 176 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(0))) 177 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index)))) 178 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_MS_ADDRESS, []byte(addr.To4()))) 179 return gtpPDPGet(req) 180 } 181 182 func GTPPDPByMSAddress(link Link, addr net.IP) (*PDP, error) { 183 return pkgHandle.GTPPDPByMSAddress(link, addr) 184 } 185 186 func (h *Handle) GTPPDPAdd(link Link, pdp *PDP) error { 187 f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME) 188 if err != nil { 189 return err 190 } 191 msg := &nl.Genlmsg{ 192 Command: nl.GENL_GTP_CMD_NEWPDP, 193 Version: nl.GENL_GTP_VERSION, 194 } 195 req := h.newNetlinkRequest(int(f.ID), unix.NLM_F_EXCL|unix.NLM_F_ACK) 196 req.AddData(msg) 197 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(pdp.Version))) 198 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index)))) 199 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_PEER_ADDRESS, []byte(pdp.PeerAddress.To4()))) 200 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_MS_ADDRESS, []byte(pdp.MSAddress.To4()))) 201 202 switch pdp.Version { 203 case 0: 204 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_TID, nl.Uint64Attr(pdp.TID))) 205 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_FLOW, nl.Uint16Attr(pdp.Flow))) 206 case 1: 207 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_I_TEI, nl.Uint32Attr(pdp.ITEI))) 208 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_O_TEI, nl.Uint32Attr(pdp.OTEI))) 209 default: 210 return fmt.Errorf("unsupported GTP version: %d", pdp.Version) 211 } 212 _, err = req.Execute(unix.NETLINK_GENERIC, 0) 213 return err 214 } 215 216 func GTPPDPAdd(link Link, pdp *PDP) error { 217 return pkgHandle.GTPPDPAdd(link, pdp) 218 } 219 220 func (h *Handle) GTPPDPDel(link Link, pdp *PDP) error { 221 f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME) 222 if err != nil { 223 return err 224 } 225 msg := &nl.Genlmsg{ 226 Command: nl.GENL_GTP_CMD_DELPDP, 227 Version: nl.GENL_GTP_VERSION, 228 } 229 req := h.newNetlinkRequest(int(f.ID), unix.NLM_F_EXCL|unix.NLM_F_ACK) 230 req.AddData(msg) 231 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(pdp.Version))) 232 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index)))) 233 234 switch pdp.Version { 235 case 0: 236 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_TID, nl.Uint64Attr(pdp.TID))) 237 case 1: 238 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_I_TEI, nl.Uint32Attr(pdp.ITEI))) 239 default: 240 return fmt.Errorf("unsupported GTP version: %d", pdp.Version) 241 } 242 _, err = req.Execute(unix.NETLINK_GENERIC, 0) 243 return err 244 } 245 246 func GTPPDPDel(link Link, pdp *PDP) error { 247 return pkgHandle.GTPPDPDel(link, pdp) 248 }