Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace netutils.py with from-scratch implementation under Apache 2.0 license #211

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ on:
jobs:
verify-python:
name: Python code verification (src)
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Install dependencies
Expand All @@ -26,7 +26,7 @@ jobs:
run: |
make test
test:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
publish-to-pypi:
name: Publish a Python distribution to PyPI
if: ${{ github.repository == 'p4lang/ptf' }}
runs-on: [ubuntu-latest]
runs-on: [ubuntu-22.04]
steps:
- uses: actions/checkout@v4
- name: Set up Python
Expand Down
120 changes: 71 additions & 49 deletions src/ptf/netutils.py
Original file line number Diff line number Diff line change
@@ -1,68 +1,90 @@
"""
Network utilities for the OpenFlow test framework
"""
# Copyright 2025 Andy Fingerhut
#
# 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.
#
# SPDX-License-Identifier: Apache-2.0

###########################################################################
## ##
## Promiscuous mode enable/disable ##
## ##
## Based on code from Scapy by Phillippe Biondi ##
## ##
## ##
## This program is free software; you can redistribute it and/or modify it ##
## under the terms of the GNU General Public License as published by the ##
## Free Software Foundation; either version 2, or (at your option) any ##
## later version. ##
## ##
## This program is distributed in the hope that it will be useful, but ##
## WITHOUT ANY WARRANTY; without even the implied warranty of ##
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ##
## General Public License for more details. ##
## ##
#############################################################################
# Note: Earlier versions of this file were licensed with a copyleft
# license.
#
# This version has been rewritten from scratch, with no reference to
# the implementations in file netutils.py earlier in the commit log of
# the repository https://github.com/p4lang/ptf

######################################################################
# get_mac:
#
# The new get_mac is copied from the Apache-2.0 implementation
# in source file ptf_nn_agent.py of this repo.

######################################################################
# set_promisc:
#
# StackOverflow answer explaining one way to do it at [2].
# [2] https://stackoverflow.com/questions/6067405/python-sockets-enabling-promiscuous-mode-in-linux

######################################################################
#
# Promiscuous mode enable/disable

import ctypes
import fcntl
import socket
from fcntl import ioctl
import struct

# From net/if_arp.h
ARPHDR_ETHER = 1
ARPHDR_LOOPBACK = 772
# Constant from Linux /usr/include/linux/if.h or net/if.h
IFF_PROMISC = 0x100

# From bits/ioctls.h
# Constants from Linux bits/ioctls.h or linux/sockios.h
SIOCGIFHWADDR = 0x8927 # Get hardware address
SIOCGIFINDEX = 0x8933 # name -> if_index mapping
SIOCGIFFLAGS = 0x8913
SIOCSIFFLAGS = 0x8914

# From netpacket/packet.h
PACKET_ADD_MEMBERSHIP = 1
PACKET_DROP_MEMBERSHIP = 2
PACKET_MR_PROMISC = 1

# From bits/socket.h
SOL_PACKET = 263
class ifreq(ctypes.Structure):
_fields_ = [("ifr_ifrn", ctypes.c_char * 16), ("ifr_flags", ctypes.c_short)]


def get_if(iff, cmd):
def get_if(iff: str, cmd: int) -> bytes:
s = socket.socket()
ifreq = ioctl(s, cmd, struct.pack("16s16x", iff.encode("utf-8")))
ifreq = fcntl.ioctl(s, cmd, struct.pack("16s16x", iff.encode("utf-8")))
s.close()
return ifreq


def get_if_index(iff):
return int(struct.unpack("I", get_if(iff, SIOCGIFINDEX)[16:20])[0])


def get_mac(iff):
return ":".join(["%02x" % ord(char) for char in get_if(iff, SIOCGIFHWADDR)[18:24]])
# Given iff, the name of a network interface (e.g. 'veth0') as a
# string, return a string of the form 'xx:yy:zz:aa:bb:cc' containing
# the MAC address of that interface, where all digits are hexadecimal.
def get_mac(iff: str) -> str:
return ":".join(
["%02x" % char for char in bytearray(get_if(iff, SIOCGIFHWADDR)[18:24])]
)


# Given iff, the name of a network interface (e.g. 'veth0') as a
# string, and s, a SOCK_RAW socket bound to that interface, set the
# interface in promiscuous mode if parameter val != 0, or into
# non-promiscuous mode if val == 0.
def set_promisc(s, iff, val=1):
mreq = struct.pack(
"IHH8s", get_if_index(iff), PACKET_MR_PROMISC, 0, "".encode("utf-8")
)
if val:
cmd = PACKET_ADD_MEMBERSHIP
ifr = ifreq()
ifr.ifr_ifrn = bytes(iff, "utf-8")
# Get current interface flags
s_fileno = s.fileno()
fcntl.ioctl(s_fileno, SIOCGIFFLAGS, ifr)
orig_flags = ifr.ifr_flags
if val != 0:
ifr.ifr_flags |= IFF_PROMISC
else:
cmd = PACKET_DROP_MEMBERSHIP
s.setsockopt(SOL_PACKET, cmd, mreq)
ifr.ifr_flags &= ~IFF_PROMISC
# Set flags, if they have changed
if ifr.ifr_flags != orig_flags:
fcntl.ioctl(s_fileno, SIOCSIFFLAGS, ifr)
2 changes: 1 addition & 1 deletion src/ptf/packet.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
""" A pluggable packet module
"""A pluggable packet module

This module dynamically imports definitions from packet manipulation module,
specified in config or provided as an agrument.
Expand Down