├── .flake8 ├── .github ├── FUNDING.yml ├── dependabot.yml └── workflows │ ├── codeql.yaml │ ├── depsreview.yaml │ ├── full.yml │ ├── pull_request.yml │ └── push.yml ├── .gitignore ├── .mypy-check-paths ├── .pre-commit-config.yaml ├── CHANGELOG.rst ├── LICENSE ├── LICENSE.Apache-2.0 ├── LICENSE.GPL-2.0-or-later ├── MANIFEST.in ├── Makefile ├── README.contribute.rst ├── README.license.rst ├── README.minimal.rst ├── README.report.rst ├── README.rst ├── VERSION ├── docs ├── Makefile ├── README.md ├── _static │ ├── .empty │ ├── classic.css │ ├── custom.css │ └── fixup.js ├── _templates │ ├── .empty │ └── layout.html ├── aafigure.map ├── arch.rst ├── asyncio.rst ├── conf.py ├── debug.rst ├── deprecated.rst ├── dhcp-server-detector.rst ├── event.rst ├── fixtures.rst ├── index.rst ├── iproute.rst ├── iproute_intro.rst ├── iproute_linux.rst ├── iproute_netns.rst ├── iproute_platforms.rst.disabled ├── iproute_responses.rst ├── iproute_tc.rst.disabled ├── ipset.rst ├── mpls.rst ├── ndb.rst ├── ndb_addresses.rst ├── ndb_auth.rst ├── ndb_debug.rst ├── ndb_init.rst ├── ndb_interfaces.rst ├── ndb_objects.rst ├── ndb_probes.rst ├── ndb_reports.rst ├── ndb_routes.rst ├── ndb_schema.rst ├── ndb_sources.rst ├── ndb_toc.rst ├── ndb_transactions.rst ├── ndb_views.rst ├── netlink.rst ├── netns.rst ├── nlsocket.rst.disabled ├── parser.rst ├── plan9.rst ├── pyroute2-cli.rst ├── pyroute2-dhcp-client.rst ├── remote.rst.disabled ├── threading.rst ├── usage.rst ├── wireguard.rst └── wiset.rst ├── examples ├── README.md ├── devlink │ ├── devlink_list.py │ ├── devlink_monitor.py │ └── devlink_port_list.py ├── ethtool │ ├── ethtool-ioctl_get_infos.py │ ├── ethtool-netlink_get_infos.py │ └── ethtool_get_infos.py ├── generic │ ├── Makefile │ ├── netl.c │ └── netl.py ├── ipq.py ├── iproute │ ├── ip_monitor.py │ └── socketcan.py ├── ipset.py ├── kobject_uevent.py ├── ndb │ ├── create_bond.py │ ├── create_interface.py │ ├── create_vlan.py │ ├── keystone_auth.py │ └── radius_auth.py ├── nftables.py ├── nftables_sets.py ├── policy │ └── policy.py ├── processes │ ├── pmonitor.py │ └── taskstats.py ├── pyroute2-cli │ ├── comments │ ├── create_bridge │ ├── create_dummy │ └── dump_lo └── wifi │ ├── nl80211_interface_type.py │ ├── nl80211_interfaces.py │ ├── nl80211_monitor.py │ ├── nl80211_scan_dump.py │ └── nl80211_set_type.py ├── noxfile.py ├── pyproject.toml ├── pyroute2 ├── __init__.py ├── arp.py ├── bsd │ ├── README │ ├── __init__.py │ ├── pf_route │ │ ├── __init__.py │ │ ├── freebsd.py │ │ └── openbsd.py │ ├── rtmsocket │ │ ├── __init__.py │ │ ├── freebsd.py │ │ └── openbsd.py │ └── util.py ├── cli │ ├── __init__.py │ ├── auth │ │ ├── __init__.py │ │ ├── auth_keystone.py │ │ └── auth_radius.py │ ├── console.py │ ├── parser.py │ ├── server.py │ └── session.py ├── common.py ├── compat.py ├── config │ ├── __init__.py │ ├── asyncio.py │ ├── eventlet.py │ ├── log.py │ └── test_platform.py ├── conntrack.py ├── decoder │ ├── __init__.py │ ├── args.py │ ├── loader.py │ └── main.py ├── devlink.py ├── dhcp │ ├── __init__.py │ ├── cli.py │ ├── client.py │ ├── dhcp4msg.py │ ├── dhcp4socket.py │ ├── enums │ │ ├── __init__.py │ │ ├── bootp.py │ │ └── dhcp.py │ ├── fsm.py │ ├── hooks.py │ ├── iface_status.py │ ├── leases.py │ ├── messages.py │ ├── server_detector.py │ ├── timers.py │ └── xids.py ├── ethtool │ ├── __init__.py │ ├── common.py │ ├── ethtool.py │ └── ioctl.py ├── ext │ ├── __init__.py │ ├── bpf.py │ ├── icmp.py │ └── rawsocket.py ├── fixtures │ ├── __init__.py │ ├── doctest.py │ ├── iproute.py │ └── plan9.py ├── inotify │ ├── __init__.py │ ├── inotify_fd.py │ └── inotify_msg.py ├── ipdb │ └── __init__.py ├── iproute │ ├── __init__.py │ ├── bsd.py │ ├── darwin.py │ ├── ipmock.py │ ├── linux.py │ ├── parsers.py │ └── windows.py ├── ipset.py ├── ipvs.py ├── iwutil.py ├── minimal.py ├── ndb │ ├── __init__.py │ ├── auth_manager.py │ ├── cli.py │ ├── cluster.py │ ├── compat.py │ ├── events.py │ ├── main.py │ ├── messages.py │ ├── objects │ │ ├── __init__.py │ │ ├── address.py │ │ ├── interface.py │ │ ├── neighbour.py │ │ ├── netns.py │ │ ├── probe.py │ │ ├── route.py │ │ └── rule.py │ ├── query.py │ ├── report.py │ ├── schema.py │ ├── source.py │ ├── task_manager.py │ ├── transaction.py │ ├── transport.py │ └── view.py ├── netlink │ ├── __init__.py │ ├── buffer.py │ ├── connector │ │ ├── __init__.py │ │ └── cn_proc.py │ ├── core.py │ ├── coredata.py │ ├── devlink │ │ └── __init__.py │ ├── diag │ │ ├── __init__.py │ │ └── ss2.py │ ├── event │ │ ├── __init__.py │ │ ├── acpi_event.py │ │ ├── dquot.py │ │ └── thermal.py │ ├── exceptions.py │ ├── generic │ │ ├── __init__.py │ │ ├── ethtool.py │ │ ├── ipvs.py │ │ ├── l2tp.py │ │ ├── mptcp.py │ │ └── wireguard.py │ ├── ipq │ │ └── __init__.py │ ├── marshal.py │ ├── nfnetlink │ │ ├── __init__.py │ │ ├── ipset.py │ │ ├── nfctsocket.py │ │ └── nftsocket.py │ ├── nl80211 │ │ └── __init__.py │ ├── nlsocket.py │ ├── rtnl │ │ ├── __init__.py │ │ ├── errmsg.py │ │ ├── fibmsg.py │ │ ├── ifaddrmsg.py │ │ ├── ifinfmsg │ │ │ ├── __init__.py │ │ │ ├── plugins │ │ │ │ ├── __init__.py │ │ │ │ ├── bond.py │ │ │ │ ├── can.py │ │ │ │ ├── geneve.py │ │ │ │ ├── gtp.py │ │ │ │ ├── ipoib.py │ │ │ │ ├── ipvlan.py │ │ │ │ ├── team.py │ │ │ │ ├── tun.py │ │ │ │ ├── tuntap.py │ │ │ │ ├── vlan.py │ │ │ │ ├── vrf.py │ │ │ │ ├── vti.py │ │ │ │ ├── vti6.py │ │ │ │ ├── vxlan.py │ │ │ │ └── xfrm.py │ │ │ └── tuntap.py │ │ ├── ifstatsmsg.py │ │ ├── iprsocket.py │ │ ├── iw_event.py │ │ ├── marshal.py │ │ ├── ndmsg.py │ │ ├── ndtmsg.py │ │ ├── nsidmsg.py │ │ ├── nsinfmsg.py │ │ ├── p2pmsg.py │ │ ├── probe_msg.py │ │ ├── rtgenmsg.py │ │ ├── rtmsg.py │ │ └── tcmsg │ │ │ ├── README.md │ │ │ ├── __init__.py │ │ │ ├── act_bpf.py │ │ │ ├── act_connmark.py │ │ │ ├── act_gact.py │ │ │ ├── act_mirred.py │ │ │ ├── act_police.py │ │ │ ├── act_skbedit.py │ │ │ ├── act_vlan.py │ │ │ ├── cls_basic.py │ │ │ ├── cls_flow.py │ │ │ ├── cls_fw.py │ │ │ ├── cls_matchall.py │ │ │ ├── cls_u32.py │ │ │ ├── common.py │ │ │ ├── common_act.py │ │ │ ├── common_ematch.py │ │ │ ├── em_cmp.py │ │ │ ├── em_ipset.py │ │ │ ├── em_meta.py │ │ │ ├── sched_bpf.py │ │ │ ├── sched_cake.py │ │ │ ├── sched_choke.py │ │ │ ├── sched_clsact.py │ │ │ ├── sched_codel.py │ │ │ ├── sched_drr.py │ │ │ ├── sched_fq_codel.py │ │ │ ├── sched_hfsc.py │ │ │ ├── sched_htb.py │ │ │ ├── sched_ingress.py │ │ │ ├── sched_netem.py │ │ │ ├── sched_pfifo.py │ │ │ ├── sched_pfifo_fast.py │ │ │ ├── sched_plug.py │ │ │ ├── sched_sfq.py │ │ │ ├── sched_tbf.py │ │ │ └── sched_template.py │ ├── taskstats │ │ └── __init__.py │ └── uevent │ │ └── __init__.py ├── netns │ ├── __init__.py │ └── manager.py ├── nftables │ ├── __init__.py │ ├── expressions.py │ ├── main.py │ ├── parser │ │ ├── __init__.py │ │ ├── expr.py │ │ └── parser.py │ └── rule.py ├── nslink │ ├── __init__.py │ └── nspopen.py ├── plan9 │ ├── __init__.py │ ├── client.py │ ├── filesystem.py │ ├── ipc.py │ ├── plan9socket.py │ └── server.py ├── process.py ├── protocols │ └── __init__.py ├── requests │ ├── __init__.py │ ├── address.py │ ├── bridge.py │ ├── common.py │ ├── link.py │ ├── main.py │ ├── neighbour.py │ ├── netns.py │ ├── probe.py │ ├── route.py │ ├── rule.py │ └── tc.py ├── statsd.py └── wiset.py ├── requirements.dev.txt ├── requirements.docs.txt ├── requirements.repo.txt ├── setup.cfg ├── setup.minimal.cfg ├── setup.py ├── tests ├── mocklib │ ├── dateutil │ │ ├── __init__.py │ │ └── parser.py │ ├── keystoneauth1 │ │ ├── __init__.py │ │ ├── identity │ │ │ ├── __init__.py │ │ │ └── v3.py │ │ └── session │ │ │ └── __init__.py │ ├── keystoneclient │ │ ├── __init__.py │ │ └── v3 │ │ │ ├── __init__.py │ │ │ ├── client.py │ │ │ └── tokens.py │ └── pyrad │ │ ├── __init__.py │ │ ├── client.py │ │ ├── dictionary.py │ │ └── packet.py ├── net_tools.py ├── test_ci │ ├── conftest.py │ └── test_fixtures.py ├── test_core │ ├── conftest.py │ ├── test_check_tid.py │ ├── test_event_loop.py │ ├── test_ipr │ │ ├── test_addr_async.py │ │ ├── test_addr_sync.py │ │ ├── test_ensure_async.py │ │ ├── test_ensure_sync.py │ │ ├── test_link_async.py │ │ ├── test_link_sync.py │ │ ├── test_route_async.py │ │ ├── test_route_dump_async.py │ │ ├── test_route_dump_sync.py │ │ ├── test_route_sync.py │ │ ├── test_rule_async.py │ │ ├── test_rule_sync.py │ │ ├── test_tc_async.py │ │ └── test_tc_sync.py │ ├── test_nftables │ │ ├── test_expressions.py │ │ └── test_nftsocket.py │ ├── test_plan9 │ │ └── test_basic.py │ ├── test_socket_create.py │ └── test_statsd.py ├── test_decoder │ ├── nl0.json │ ├── nl0.pcap │ └── test_pcap.py ├── test_integration │ ├── conftest.py │ ├── test_kuryr.py │ ├── test_lnst.py │ ├── test_octavia.py │ ├── test_os_vif.py │ └── test_ovn_bgp_agent.py ├── test_limits │ ├── conftest.py │ ├── test_nl.py │ └── test_stress.py ├── test_linux │ ├── conftest.py │ ├── fixtures │ │ ├── dhcp_servers │ │ │ ├── __init__.py │ │ │ ├── dnsmasq.py │ │ │ ├── mock.py │ │ │ └── udhcpd.py │ │ ├── interfaces.py │ │ └── pcap_files.py │ ├── pr2test │ │ ├── __init__.py │ │ ├── context_manager.py │ │ ├── custom_link_kind │ │ │ ├── __init__.py │ │ │ └── foo.py │ │ ├── marks.py │ │ └── tools.py │ ├── test_api │ │ └── __init__.py │ ├── test_connector │ │ └── test_cn_proc.py │ ├── test_conntrack.py │ ├── test_devlink.py │ ├── test_dhcp │ │ ├── captures │ │ │ ├── test_parser │ │ │ │ ├── test_android_reboot_request.pcap │ │ │ │ ├── test_android_tethering_renew.pcap │ │ │ │ ├── test_decode_simple_lease_process.pcap │ │ │ │ ├── test_huawei_discover_option_148.pcap │ │ │ │ ├── test_invalid_client_id_option.pcap │ │ │ │ ├── test_invalid_router_option.pcap │ │ │ │ ├── test_netatmo_discover_request.pcap │ │ │ │ ├── test_truncated_packet.pcap │ │ │ │ ├── test_washing_machine_request.pcap │ │ │ │ └── test_wii_discover.pcap │ │ │ └── test_unit │ │ │ │ ├── test_ack_invalid_request_state.pcap │ │ │ │ ├── test_get_and_renew_lease.pcap │ │ │ │ ├── test_init_reboot_nak.pcap │ │ │ │ ├── test_offer_wrong_xid.pcap │ │ │ │ ├── test_requesting_timeout.pcap │ │ │ │ ├── test_truncated_packet.pcap │ │ │ │ ├── test_unexpected_dhcp_message.pcap │ │ │ │ └── test_unknown_message.pcap │ │ ├── conftest.py │ │ ├── test_cli.py │ │ ├── test_encode.py │ │ ├── test_hooks.py │ │ ├── test_integration.py │ │ ├── test_parser.py │ │ ├── test_server_detector.py │ │ └── test_unit.py │ ├── test_diag.py │ ├── test_dquot │ │ ├── dquot.img.gz │ │ └── test_dquot.py │ ├── test_ethtool.py │ ├── test_generic │ │ ├── __init__.py │ │ ├── test_basic.py │ │ ├── test_l2tp.py │ │ ├── test_mptcp.py │ │ └── test_taskstats.py │ ├── test_integration │ │ └── test_serialize.py │ ├── test_ipr │ │ ├── __init__.py │ │ ├── test_addr.py │ │ ├── test_basic.py │ │ ├── test_callbacks.py │ │ ├── test_compile.py │ │ ├── test_config.py │ │ ├── test_fdb.py │ │ ├── test_ipbatch.py │ │ ├── test_link.py │ │ ├── test_link_create.py │ │ ├── test_link_custom_kind.py │ │ ├── test_match.py │ │ ├── test_neigh.py │ │ ├── test_netns.py │ │ ├── test_ntables.py │ │ ├── test_probe.py │ │ ├── test_route.py │ │ ├── test_rule.py │ │ ├── test_stress.py │ │ ├── test_vlan.py │ │ └── test_vlan_filter.py │ ├── test_ipset.py │ ├── test_ipvs.py │ ├── test_iwutil.py │ ├── test_ndb │ │ ├── __init__.py │ │ ├── test_address.py │ │ ├── test_altnames.py │ │ ├── test_backup.py │ │ ├── test_chaotic.py │ │ ├── test_db.py │ │ ├── test_ensure.py │ │ ├── test_examples.py │ │ ├── test_fdb.py │ │ ├── test_init.py │ │ ├── test_interface_create.py │ │ ├── test_interface_set.py │ │ ├── test_mpls.py │ │ ├── test_neighbour.py │ │ ├── test_netns.py │ │ ├── test_probe.py │ │ ├── test_reports.py │ │ ├── test_rollback.py │ │ ├── test_routes.py │ │ ├── test_rules.py │ │ ├── test_sources.py │ │ ├── test_syntax.py │ │ ├── test_transaction.py │ │ └── test_views.py │ ├── test_netns │ │ └── test_nspopen.py │ ├── test_nlmsg │ │ └── test_nlmsg.py │ ├── test_tc │ │ ├── __init__.py │ │ ├── test_actions.py │ │ ├── test_basic.py │ │ ├── test_bpf.py │ │ ├── test_classful.py │ │ ├── test_htb.py │ │ └── test_ingress.py │ ├── test_wireguard │ │ ├── __init__.py │ │ └── test_peer.py │ └── test_wiset.py ├── test_minimal │ └── test_iproute.py ├── test_neutron │ └── test_ip_lib.py ├── test_openbsd │ ├── conftest.py │ └── test_ipr │ │ └── test_basic.py ├── test_process │ ├── test_basic.py │ └── test_catastrophe.py ├── test_repo │ ├── test_minimal.py │ ├── test_noxfile.py │ └── test_version.py ├── test_unit │ ├── test_addr_pool.py │ ├── test_buffer.py │ ├── test_common.py │ ├── test_config.py │ ├── test_entry_points │ │ └── test_basic.py │ ├── test_iproute_match │ │ ├── links.dump │ │ └── test_match.py │ ├── test_nlmsg │ │ ├── addrmsg_ipv4.dump │ │ ├── gre_01.dump │ │ ├── iw_info_rsp.dump │ │ ├── iw_scan_rsp.dump │ │ ├── test_attr.py │ │ ├── test_map_adapter.py │ │ ├── test_marshal.py │ │ ├── uevent_kernel_backlight.dump │ │ └── uevent_udevd_backlight.dump │ └── test_requests │ │ ├── common.py │ │ ├── test_address.py │ │ ├── test_link.py │ │ ├── test_neighbour.py │ │ └── test_route.py ├── test_windows │ └── test_ipr.py └── utils.py └── util ├── aafigure_mapper.py ├── aafigure_mapper.sh ├── find_python.sh ├── imports_dict.awk └── update_version.py /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | 3 | ignore = E203,E722,W503 4 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: svinota 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yaml: -------------------------------------------------------------------------------- 1 | name: "Code Scanning - Action" 2 | 3 | on: 4 | pull_request: 5 | push: 6 | 7 | jobs: 8 | CodeQL-Build: 9 | # CodeQL runs on ubuntu-latest, windows-latest, and macos-latest 10 | runs-on: ubuntu-latest 11 | 12 | permissions: 13 | # required for all workflows 14 | security-events: write 15 | 16 | steps: 17 | - name: Checkout repository 18 | uses: actions/checkout@v4 19 | 20 | # Initializes the CodeQL tools for scanning. 21 | - name: Initialize CodeQL 22 | uses: github/codeql-action/init@v3 23 | # Override language selection by uncommenting this and choosing your languages 24 | # with: 25 | # languages: go, javascript, csharp, python, cpp, java 26 | 27 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 28 | # If this step fails, then you should remove it and run the build manually (see below). 29 | - name: Autobuild 30 | uses: github/codeql-action/autobuild@v3 31 | 32 | # ℹ️ Command-line programs to run using the OS shell. 33 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 34 | 35 | # ✏️ If the Autobuild fails above, remove it and uncomment the following 36 | # three lines and modify them (or add more) to build your code if your 37 | # project uses a compiled language 38 | 39 | #- run: | 40 | # make bootstrap 41 | # make release 42 | 43 | - name: Perform CodeQL Analysis 44 | uses: github/codeql-action/analyze@v3 45 | -------------------------------------------------------------------------------- /.github/workflows/depsreview.yaml: -------------------------------------------------------------------------------- 1 | name: 'Dependency Review' 2 | on: [pull_request] 3 | 4 | permissions: 5 | contents: read 6 | 7 | jobs: 8 | dependency-review: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: 'Checkout Repository' 12 | uses: actions/checkout@v4 13 | - name: 'Dependency Review' 14 | uses: actions/dependency-review-action@v4 15 | -------------------------------------------------------------------------------- /.github/workflows/push.yml: -------------------------------------------------------------------------------- 1 | name: Linter 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | workflow_dispatch: 7 | 8 | permissions: 9 | contents: read 10 | 11 | jobs: 12 | build: 13 | runs-on: Fedora 14 | strategy: 15 | matrix: 16 | python: [python3.9, python3.14] 17 | steps: 18 | - run: sudo chown -R $USER:$USER $GITHUB_WORKSPACE 19 | - uses: actions/checkout@v4 20 | - run: make nox session=linter-${{ matrix.python }} 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .eggs/ 3 | *.swp 4 | *.pyc 5 | *~ 6 | pyroute2/config/version.py 7 | build/ 8 | dist/ 9 | MANIFEST 10 | docs/html 11 | docs/man 12 | docs/doctrees 13 | docs/_templates/private.layout.html 14 | docs-build.log 15 | lab/_build 16 | lab/*html 17 | lab/_static/conf.js 18 | *.egg-info 19 | benchmark.log 20 | venv 21 | .venv 22 | .nox* 23 | tests/*.db 24 | tests/*.json 25 | -------------------------------------------------------------------------------- /.mypy-check-paths: -------------------------------------------------------------------------------- 1 | pyroute2/common.py 2 | pyroute2/fixtures 3 | pyroute2/netlink/core.py 4 | pyroute2/netlink/coredata.py 5 | pyroute2/netlink/nlsocket.py 6 | pyroute2/netlink/uevent/__init__.py 7 | pyroute2/netlink/rtnl/iprsocket.py 8 | pyroute2/netlink/rtnl/ifinfmsg/tuntap.py 9 | pyroute2/netns/ 10 | pyroute2/plan9/client.py 11 | pyroute2/process.py 12 | pyroute2/statsd.py 13 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | files: '^(noxfile.py|pyroute2|pr2modules|util|examlpes/ndb|docs/conf.py|examples/pyroute2-cli|tests)' 2 | repos: 3 | - repo: https://github.com/pre-commit/pre-commit-hooks 4 | rev: v4.5.0 5 | hooks: 6 | - id: trailing-whitespace 7 | - id: end-of-file-fixer 8 | - repo: https://github.com/pycqa/isort 9 | rev: 5.13.2 10 | hooks: 11 | - id: isort 12 | name: isort (python) 13 | args: ['-m', '3', '--tc', '-w', '79', '--profile', 'black'] 14 | - repo: https://github.com/psf/black 15 | rev: 24.1.1 16 | hooks: 17 | - id: black 18 | args: ['-C', '-S', '-l', '79'] 19 | - repo: https://github.com/PyCQA/flake8 20 | rev: 7.0.0 21 | hooks: 22 | - id: flake8 23 | files: \.py$ 24 | args: ['--config', '.flake8'] 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GPL-2.0-or-later OR Apache-2.0 2 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include VERSION 2 | include README.rst 3 | include README.contribute.rst 4 | include README.minimal.rst 5 | include README.report.rst 6 | include README.license.rst 7 | include LICENSE* 8 | include CHANGELOG.rst 9 | graft docs/html 10 | graft tests/test_unit 11 | graft examples 12 | -------------------------------------------------------------------------------- /README.license.rst: -------------------------------------------------------------------------------- 1 | Pyroute2 package is dual licensed since 0.3.6, emerging two licenses: 2 | 3 | * GPL-2.0-or-later 4 | * Apache-2.0 5 | 6 | It means, that being writing some derived code, or including the 7 | library into distribution, you are free to choose the license from the 8 | list above. 9 | 10 | Apache v2 license was included to make the code compatible with the 11 | OpenStack project. 12 | -------------------------------------------------------------------------------- /README.minimal.rst: -------------------------------------------------------------------------------- 1 | pyroute2.minimal 2 | ================ 3 | 4 | PyRoute2 is a pure Python **netlink** library. 5 | 6 | This module provides minimal subset of pyroute2 modules. Only netlink parser, 7 | basic netns management and some netlink protocols implementations. 8 | 9 | links 10 | ===== 11 | 12 | * Home: 13 | * PyPI: 14 | * Usage: 15 | -------------------------------------------------------------------------------- /README.report.rst: -------------------------------------------------------------------------------- 1 | Report a bug 2 | ============ 3 | 4 | In the case you have issues, please report them to the project 5 | bug tracker: https://github.com/svinota/pyroute2/issues 6 | 7 | It is important to provide all the required information 8 | with your report: 9 | 10 | * Linux kernel version 11 | * Python version 12 | * Specific environment, if used -- gevent, eventlet etc. 13 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 0.9.2 2 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | Documentation 2 | ------------- 3 | 4 | That's the project documentation source. In order to build 5 | html docs, one should install sphinx and run `make docs` 6 | in the project's root directory. 7 | 8 | Actual built docs are available at http://docs.pyroute2.org/ 9 | -------------------------------------------------------------------------------- /docs/_static/.empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/docs/_static/.empty -------------------------------------------------------------------------------- /docs/_static/classic.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/docs/_static/classic.css -------------------------------------------------------------------------------- /docs/_templates/.empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/docs/_templates/.empty -------------------------------------------------------------------------------- /docs/_templates/layout.html: -------------------------------------------------------------------------------- 1 | {% extends '!layout.html' %} 2 | 3 | {%- macro c_relbar() %} 4 | 22 | {%- endmacro %} 23 | 24 | {% block relbar1 %} 25 | {{ c_relbar() }} 26 | {% endblock %} 27 | -------------------------------------------------------------------------------- /docs/aafigure.map: -------------------------------------------------------------------------------- 1 | source|../ndb_sources.html 2 | SQL database|../ndb_schema.html 3 | SQLite|../ndb_schema.html 4 | PostgreSQL|../ndb_schema.html 5 | NDB object:|../ndb_objects.html 6 | interface|../ndb_objects.html 7 | address|../ndb_objects.html 8 | route|../ndb_objects.html 9 | netlink events|../netlink.html 10 | inotify events|../netlink.html 11 | NDB() instance|../ndb.html 12 | View()|../ndb_objects.html 13 | .dump()|../ndb_objects.html 14 | .summary()|../ndb_objects.html 15 | RecordSet()|../ndb_reports.html 16 | filter()|../ndb_reports.html 17 | select()|../ndb_reports.html 18 | transform()|../ndb_reports.html 19 | join()|../ndb_reports.html 20 | Record()|../ndb_reports.html 21 | .create()|../ndb_objects.html 22 | .__getitem__()|../ndb_objects.html 23 | Interface()|../ndb_interfaces.html 24 | Address()|../ndb_addresses.html 25 | Route()|../ndb_routes.html 26 | Neighbour()|../ndb.html 27 | Rule()|../ndb.html 28 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | import pyroute2 2 | 3 | extensions = [ 4 | 'sphinx.ext.autodoc', 5 | 'sphinx.ext.doctest', 6 | 'sphinx.ext.inheritance_diagram', 7 | 'aafigure.sphinxext', 8 | 'code_include.extension', 9 | ] 10 | 11 | aafig_format = {'html': 'svg', 'man': None, '': None} 12 | 13 | inheritance_graph_attrs = {'rankdir': 'LR', 'ratio': 'auto'} 14 | source_suffix = '.rst' 15 | master_doc = 'index' 16 | project = u'pyroute2' 17 | copyright = u'pyroute2 team' 18 | 19 | release = pyroute2.__version__ 20 | 21 | exclude_patterns = ['_build'] 22 | pygments_style = 'sphinx' 23 | autodoc_member_order = 'bysource' 24 | 25 | html_theme = 'default' 26 | html_static_path = ['_static'] 27 | html_js_files = ['fixup.js'] 28 | html_css_files = ['custom.css'] 29 | htmlhelp_basename = 'pyroute2doc' 30 | templates_path = ['_templates'] 31 | 32 | 33 | man_pages = [ 34 | ( 35 | 'pyroute2-cli', 36 | 'pyroute2-cli', 37 | 'pyroute2 command line interface', 38 | ['Peter Saveliev'], 39 | 1, 40 | ), 41 | ( 42 | 'pyroute2-dhcp-client', 43 | 'pyroute2-dhcp-client', 44 | 'pyroute2 dhcp client', 45 | ['Étienne Noss', 'Peter Saveliev'], 46 | 1, 47 | ), 48 | ( 49 | 'dhcp-server-detector', 50 | 'dhcp-server-detector', 51 | 'dhcp server detector', 52 | ['Étienne Noss'], 53 | 1, 54 | ), 55 | ] 56 | -------------------------------------------------------------------------------- /docs/debug.rst: -------------------------------------------------------------------------------- 1 | .. debug: 2 | 3 | Netlink debugging howto 4 | ----------------------- 5 | 6 | pyroute2-decoder 7 | ================ 8 | 9 | .. automodule:: pyroute2.decoder.main 10 | :members: 11 | 12 | filter functions 13 | ================ 14 | .. automodule:: pyroute2.decoder.loader 15 | :members: MatchOps 16 | -------------------------------------------------------------------------------- /docs/deprecated.rst: -------------------------------------------------------------------------------- 1 | .. _deprecated: 2 | 3 | .. automodule:: pyroute2.ipdb 4 | -------------------------------------------------------------------------------- /docs/event.rst: -------------------------------------------------------------------------------- 1 | .. _event: 2 | 3 | Generic netlink events protocols 4 | ================================ 5 | 6 | The only available method for the event sockets is `get()` -- it returns 7 | an iterator over broadcasted messages, following the generic pyroute2 API. 8 | Even though the event protocols provide one message per `recv()`. 9 | 10 | No manual `bind()` or `discovery()` required -- the event sockets run 11 | these methods authomatically. 12 | 13 | Please keep in mind that you have to consume all the incoming messages 14 | in time, otherwise a buffer overflow happens on the socket and the only 15 | way to fix that is to `close()` the failed socket and to open a new one. 16 | 17 | ACPI events 18 | ----------- 19 | 20 | .. automodule:: pyroute2.netlink.event.acpi_event 21 | 22 | Disk quota events 23 | ----------------- 24 | 25 | .. automodule:: pyroute2.netlink.event.dquot 26 | -------------------------------------------------------------------------------- /docs/fixtures.rst: -------------------------------------------------------------------------------- 1 | .. _fixtures: 2 | 3 | .. automodule:: pyroute2.fixtures 4 | :members: 5 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. pyroute2 documentation master file 2 | 3 | Pyroute2 netlink library 4 | ======================== 5 | 6 | General information 7 | ------------------- 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | 12 | general 13 | changelog 14 | report 15 | 16 | Usage 17 | ----- 18 | 19 | .. toctree:: 20 | :maxdepth: 2 21 | 22 | usage 23 | asyncio 24 | threading 25 | iproute 26 | ndb 27 | fixtures 28 | plan9 29 | wiset 30 | ipset 31 | netns 32 | wireguard 33 | event 34 | 35 | Howtos 36 | ------ 37 | 38 | .. toctree:: 39 | :maxdepth: 2 40 | 41 | mpls 42 | debug 43 | 44 | Man pages 45 | --------- 46 | 47 | .. toctree:: 48 | :maxdepth: 1 49 | 50 | pyroute2-cli 51 | pyroute2-dhcp-client 52 | dhcp-server-detector 53 | 54 | Development 55 | ----------- 56 | 57 | .. toctree:: 58 | :maxdepth: 2 59 | 60 | devcontribute 61 | arch 62 | parser 63 | netlink 64 | 65 | Deprecated 66 | ---------- 67 | 68 | .. toctree:: 69 | :maxdepth: 1 70 | 71 | deprecated 72 | 73 | Indices and tables 74 | ================== 75 | 76 | * :ref:`genindex` 77 | * :ref:`modindex` 78 | * :ref:`search` 79 | 80 | -------------------------------------------------------------------------------- /docs/iproute.rst: -------------------------------------------------------------------------------- 1 | .. _iproute: 2 | 3 | IPRoute and related modules 4 | =========================== 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | 9 | iproute_intro 10 | iproute_netns 11 | iproute_responses 12 | iproute_linux 13 | 14 | .. 15 | excluded chapters: 16 | iproute_platforms 17 | iproute_tc 18 | -------------------------------------------------------------------------------- /docs/iproute_linux.rst: -------------------------------------------------------------------------------- 1 | .. _iproute_linux: 2 | 3 | .. testsetup:: * 4 | 5 | from pyroute2 import config, IPRoute 6 | config.mock_netlink = True 7 | ipr = IPRoute() 8 | 9 | .. testcleanup:: * 10 | 11 | ipr.close() 12 | 13 | 14 | Linux systems 15 | ------------- 16 | 17 | .. automodule:: pyroute2.iproute.linux 18 | 19 | .. autoclass:: pyroute2.iproute.linux.RTNL_API 20 | :members: 21 | -------------------------------------------------------------------------------- /docs/iproute_platforms.rst.disabled: -------------------------------------------------------------------------------- 1 | .. _iproute_platforms: 2 | 3 | Non-RTNL platforms 4 | ------------------ 5 | 6 | `pyroute2` offers experimental support for platforms that do not 7 | provide Netlink/RTNL, including BSD systems. 8 | 9 | BSD systems 10 | ~~~~~~~~~~~ 11 | 12 | .. automodule:: pyroute2.iproute.bsd 13 | 14 | Windows systems 15 | ~~~~~~~~~~~~~~~ 16 | 17 | .. automodule:: pyroute2.iproute.windows 18 | 19 | .. autoclass:: pyroute2.iproute.windows.IPRoute 20 | :members: 21 | -------------------------------------------------------------------------------- /docs/iproute_tc.rst.disabled: -------------------------------------------------------------------------------- 1 | .. _iproute_tc: 2 | 3 | Queueing disciplines 4 | -------------------- 5 | 6 | .. automodule:: pyroute2.netlink.rtnl.tcmsg.sched_drr 7 | :members: 8 | 9 | .. automodule:: pyroute2.netlink.rtnl.tcmsg.sched_choke 10 | :members: 11 | 12 | .. automodule:: pyroute2.netlink.rtnl.tcmsg.sched_clsact 13 | :members: 14 | 15 | .. automodule:: pyroute2.netlink.rtnl.tcmsg.sched_hfsc 16 | :members: 17 | 18 | .. automodule:: pyroute2.netlink.rtnl.tcmsg.sched_htb 19 | :members: 20 | 21 | Filters 22 | ------- 23 | 24 | .. automodule:: pyroute2.netlink.rtnl.tcmsg.cls_u32 25 | -------------------------------------------------------------------------------- /docs/ipset.rst: -------------------------------------------------------------------------------- 1 | .. ipset: 2 | 3 | IPSet module 4 | ============== 5 | 6 | .. automodule:: pyroute2.ipset 7 | :members: 8 | -------------------------------------------------------------------------------- /docs/ndb.rst: -------------------------------------------------------------------------------- 1 | .. _ndb: 2 | 3 | NDB module intro 4 | ================ 5 | 6 | .. automodule:: pyroute2.ndb.main 7 | 8 | NDB reference 9 | ============= 10 | 11 | .. include:: ndb_toc.rst 12 | -------------------------------------------------------------------------------- /docs/ndb_addresses.rst: -------------------------------------------------------------------------------- 1 | .. ndbaddresses: 2 | 3 | IP addresses management 4 | ======================= 5 | 6 | .. automodule:: pyroute2.ndb.objects.address 7 | -------------------------------------------------------------------------------- /docs/ndb_auth.rst: -------------------------------------------------------------------------------- 1 | .. _ndbauth: 2 | 3 | Authorization plugins 4 | ===================== 5 | 6 | .. automodule:: pyroute2.ndb.auth_manager 7 | 8 | Usecase: OpenStack Keystone auth 9 | -------------------------------- 10 | 11 | Say we have a public service that provides access to NDB instance via 12 | HTTP, and authenticates users via Keystone. Then the auth flow could be: 13 | 14 | 1. Accept a connection from a client 15 | 2. Create custom auth manager object A 16 | 3. A.__init__() validates X-Auth-Token against Keystone (Authentication) 17 | 4. A.check() checks that X-Auth-Token is not expired (Authorization) 18 | 5. The auth result is being logged (Accounting) 19 | 20 | An example AuthManager with OpenStack APIv3 support you may find in the 21 | `/examples/ndb/` directory. 22 | 23 | .. literalinclude:: ../examples/ndb/keystone_auth.py 24 | :language: python 25 | :caption: keystone_auth.py 26 | :name: keystone_auth 27 | 28 | Usecase: RADIUS auth 29 | -------------------- 30 | 31 | .. literalinclude:: ../examples/ndb/radius_auth.py 32 | :language: python 33 | :caption: radius_auth.py 34 | :name: radius_auth 35 | -------------------------------------------------------------------------------- /docs/ndb_interfaces.rst: -------------------------------------------------------------------------------- 1 | .. _ndbinterfaces: 2 | 3 | Network interfaces 4 | ================== 5 | 6 | .. automodule:: pyroute2.ndb.objects.interface 7 | -------------------------------------------------------------------------------- /docs/ndb_objects.rst: -------------------------------------------------------------------------------- 1 | .. ndbobjects: 2 | 3 | RTNL objects 4 | ============ 5 | 6 | .. automodule:: pyroute2.ndb.objects 7 | 8 | .. autoclass:: pyroute2.ndb.objects.RTNL_Object() 9 | 10 | .. autoproperty:: table 11 | .. autoproperty:: etable 12 | .. autoproperty:: key 13 | .. automethod:: apply 14 | .. automethod:: commit 15 | .. automethod:: complete_key 16 | .. automethod:: create(**spec) 17 | .. automethod:: exists 18 | .. automethod:: load_sql 19 | .. automethod:: load_value 20 | .. automethod:: set(key, value) 21 | .. automethod:: show(fmt) 22 | .. automethod:: snapshot 23 | .. automethod:: rollback 24 | -------------------------------------------------------------------------------- /docs/ndb_probes.rst: -------------------------------------------------------------------------------- 1 | .. ndbprobes: 2 | 3 | Network probes 4 | ============== 5 | 6 | .. automodule:: pyroute2.ndb.objects.probe 7 | -------------------------------------------------------------------------------- /docs/ndb_reports.rst: -------------------------------------------------------------------------------- 1 | .. _ndbreports: 2 | 3 | Record list filters 4 | =================== 5 | 6 | .. automodule:: pyroute2.ndb.report 7 | :members: 8 | -------------------------------------------------------------------------------- /docs/ndb_routes.rst: -------------------------------------------------------------------------------- 1 | .. _ndbroutes: 2 | 3 | Routes management 4 | ================= 5 | 6 | .. automodule:: pyroute2.ndb.objects.route 7 | -------------------------------------------------------------------------------- /docs/ndb_schema.rst: -------------------------------------------------------------------------------- 1 | .. _ndbschema: 2 | 3 | Database 4 | ======== 5 | 6 | .. automodule:: pyroute2.ndb.schema 7 | -------------------------------------------------------------------------------- /docs/ndb_sources.rst: -------------------------------------------------------------------------------- 1 | .. _ndbsources: 2 | 3 | RTNL sources 4 | ============ 5 | 6 | .. automodule:: pyroute2.ndb.source 7 | -------------------------------------------------------------------------------- /docs/ndb_toc.rst: -------------------------------------------------------------------------------- 1 | .. _ndb_toc: 2 | 3 | .. toctree:: 4 | :maxdepth: 2 5 | 6 | ndb_init 7 | ndb_objects 8 | ndb_views 9 | ndb_transactions 10 | ndb_reports 11 | ndb_interfaces 12 | ndb_addresses 13 | ndb_routes 14 | ndb_probes 15 | ndb_schema 16 | ndb_sources 17 | ndb_debug 18 | ndb_auth 19 | -------------------------------------------------------------------------------- /docs/ndb_transactions.rst: -------------------------------------------------------------------------------- 1 | 2 | .. ndbtransactions: 3 | 4 | Transactions 5 | ============ 6 | 7 | .. automodule:: pyroute2.ndb.transaction 8 | :members: 9 | -------------------------------------------------------------------------------- /docs/ndb_views.rst: -------------------------------------------------------------------------------- 1 | .. ndbviews: 2 | 3 | Views 4 | ===== 5 | 6 | .. automodule:: pyroute2.ndb.view 7 | 8 | .. autoclass:: pyroute2.ndb.view.View() 9 | :members: 10 | -------------------------------------------------------------------------------- /docs/netlink.rst: -------------------------------------------------------------------------------- 1 | .. netlink: 2 | 3 | .. automodule:: pyroute2.netlink 4 | -------------------------------------------------------------------------------- /docs/netns.rst: -------------------------------------------------------------------------------- 1 | .. _netns: 2 | 3 | NetNS management 4 | ================ 5 | 6 | .. automodule:: pyroute2.netns 7 | :members: create, 8 | remove, 9 | attach, 10 | setns, 11 | pushns, 12 | popns, 13 | dropns, 14 | listnetns, 15 | ns_pids, 16 | pid_to_ns 17 | 18 | .. automodule:: pyroute2.nslink.nspopen 19 | :members: 20 | -------------------------------------------------------------------------------- /docs/nlsocket.rst.disabled: -------------------------------------------------------------------------------- 1 | .. nlsocket: 2 | 3 | .. automodule:: pyroute2.netlink.nlsocket 4 | :members: 5 | -------------------------------------------------------------------------------- /docs/plan9.rst: -------------------------------------------------------------------------------- 1 | .. _plan9: 2 | 3 | .. testsetup:: 4 | 5 | import asyncio 6 | 7 | from pyroute2.plan9.server import Plan9ServerSocket 8 | from pyroute2.plan9.client import Plan9ClientSocket 9 | 10 | 11 | Plan9 9p2000 protocol 12 | ===================== 13 | 14 | The library provides basic asynchronous 9p2000 implementation. 15 | 16 | .. autoclass:: pyroute2.plan9.server.Plan9ServerSocket 17 | :members: 18 | 19 | .. autoclass:: pyroute2.plan9.client.Plan9ClientSocket 20 | :members: 21 | -------------------------------------------------------------------------------- /docs/wireguard.rst: -------------------------------------------------------------------------------- 1 | .. _wireguard: 2 | 3 | WireGuard module 4 | ================ 5 | 6 | .. automodule:: pyroute2.netlink.generic.wireguard 7 | -------------------------------------------------------------------------------- /docs/wiset.rst: -------------------------------------------------------------------------------- 1 | .. wiset: 2 | 3 | WiSet module 4 | ============ 5 | 6 | .. automodule:: pyroute2.wiset 7 | :members: 8 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | Examples 2 | ======== 3 | -------------------------------------------------------------------------------- /examples/devlink/devlink_list.py: -------------------------------------------------------------------------------- 1 | from pyroute2 import DL 2 | 3 | dl = DL() 4 | for q in dl.get_dump(): 5 | print( 6 | '%s\t%s' 7 | % ( 8 | q.get_attr('DEVLINK_ATTR_BUS_NAME'), 9 | q.get_attr('DEVLINK_ATTR_DEV_NAME'), 10 | ) 11 | ) 12 | dl.close() 13 | -------------------------------------------------------------------------------- /examples/devlink/devlink_monitor.py: -------------------------------------------------------------------------------- 1 | from pyroute2.devlink import DL 2 | 3 | 4 | dl = DL(groups=~0) 5 | print(dl.get()) 6 | dl.close() 7 | -------------------------------------------------------------------------------- /examples/devlink/devlink_port_list.py: -------------------------------------------------------------------------------- 1 | from pyroute2 import DL 2 | 3 | dl = DL() 4 | for q in dl.get_port_dump(): 5 | print( 6 | '%s\t%s\t%u' 7 | % ( 8 | q.get_attr('DEVLINK_ATTR_BUS_NAME'), 9 | q.get_attr('DEVLINK_ATTR_DEV_NAME'), 10 | q.get_attr('DEVLINK_ATTR_PORT_INDEX'), 11 | ) 12 | ) 13 | dl.close() 14 | -------------------------------------------------------------------------------- /examples/ethtool/ethtool-ioctl_get_infos.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from pyroute2.ethtool.ioctl import IoctlEthtool 3 | from pyroute2.ethtool.ioctl import NotSupportedError 4 | 5 | if len(sys.argv) != 2: 6 | raise Exception("USAGE: {0} IFNAME".format(sys.argv[0])) 7 | 8 | 9 | dev = IoctlEthtool(sys.argv[1]) 10 | print("=== Device cmd: ===") 11 | try: 12 | for name, value in dev.get_cmd().items(): 13 | print("\t{}: {}".format(name, value)) 14 | except NotSupportedError: 15 | print("Not supported by driver.\n") 16 | print("") 17 | 18 | print("=== Device feature: ===") 19 | for name, value, not_fixed, _, _ in dev.get_features(): 20 | value = "on" if value else "off" 21 | if not not_fixed: 22 | # I love double negations 23 | value += " [fixed]" 24 | print("\t{}: {}".format(name, value)) 25 | 26 | print("\n=== Device coalesce: ===") 27 | for name, value in dev.get_coalesce().items(): 28 | print("\t{}: {}".format(name, value)) 29 | 30 | print("\n=== Device statistics: ===") 31 | for name, value in dev.get_statistics(): 32 | print("\t{}: {}".format(name, value)) 33 | -------------------------------------------------------------------------------- /examples/ethtool/ethtool-netlink_get_infos.py: -------------------------------------------------------------------------------- 1 | import pprint 2 | import sys 3 | 4 | from pyroute2.netlink.generic.ethtool import NlEthtool 5 | 6 | if len(sys.argv) != 2: 7 | raise Exception("USAGE: {0} IFNAME".format(sys.argv[0])) 8 | 9 | 10 | IFNAME = sys.argv[1] 11 | eth = NlEthtool() 12 | 13 | print("kernel ok?:", eth.is_nlethtool_in_kernel()) 14 | pprint.pprint(eth.get_linkmode(IFNAME)) 15 | print("") 16 | pprint.pprint(eth.get_linkinfo(IFNAME)) 17 | print("") 18 | pprint.pprint(eth.get_stringset(IFNAME)) 19 | print("") 20 | pprint.pprint(eth.get_linkstate(IFNAME)) 21 | print("") 22 | pprint.pprint(eth.get_wol(IFNAME)) 23 | -------------------------------------------------------------------------------- /examples/ethtool/ethtool_get_infos.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from pyroute2.ethtool import Ethtool 3 | 4 | if len(sys.argv) != 2: 5 | raise Exception("USAGE: {0} IFNAME".format(sys.argv[0])) 6 | ethtool = Ethtool() 7 | ifname = sys.argv[1] 8 | 9 | print(ethtool.get_link_mode(ifname)) 10 | print(ethtool.get_link_info(ifname)) 11 | print(ethtool.get_strings_set(ifname)) 12 | print(ethtool.get_wol(ifname)) 13 | print(ethtool.get_features(ifname)) 14 | print(ethtool.get_coalesce(ifname)) 15 | -------------------------------------------------------------------------------- /examples/generic/Makefile: -------------------------------------------------------------------------------- 1 | obj-m += netl.o 2 | 3 | all: 4 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 5 | 6 | clean: 7 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 8 | 9 | -------------------------------------------------------------------------------- /examples/generic/netl.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import traceback 4 | from pyroute2.netlink import NLM_F_REQUEST 5 | from pyroute2.netlink import genlmsg 6 | from pyroute2.netlink.generic import GenericNetlinkSocket 7 | 8 | 9 | RLINK_CMD_UNSPEC = 0 10 | RLINK_CMD_REQ = 1 11 | 12 | 13 | class rcmd(genlmsg): 14 | ''' 15 | Message class that will be used to communicate 16 | with the kernel module 17 | ''' 18 | 19 | nla_map = ( 20 | ('RLINK_ATTR_UNSPEC', 'none'), 21 | ('RLINK_ATTR_DATA', 'asciiz'), 22 | ('RLINK_ATTR_LEN', 'uint32'), 23 | ) 24 | 25 | 26 | class Rlink(GenericNetlinkSocket): 27 | def send_data(self, data): 28 | msg = rcmd() 29 | msg['cmd'] = RLINK_CMD_REQ 30 | msg['version'] = 1 31 | msg['attrs'] = [('RLINK_ATTR_DATA', data)] 32 | ret = self.nlm_request(msg, self.prid, msg_flags=NLM_F_REQUEST)[0] 33 | return ret.get_attr('RLINK_ATTR_LEN') 34 | 35 | 36 | if __name__ == '__main__': 37 | try: 38 | # create protocol instance 39 | rlink = Rlink() 40 | rlink.bind('EXMPL_GENL', rcmd) 41 | # request a method 42 | print(rlink.send_data('x' * 65000)) 43 | except: 44 | # if there was an error, log it to the console 45 | traceback.print_exc() 46 | finally: 47 | # finally -- release the instance 48 | rlink.close() 49 | -------------------------------------------------------------------------------- /examples/ipq.py: -------------------------------------------------------------------------------- 1 | from pyroute2.common import hexdump 2 | from pyroute2 import IPQSocket 3 | from pyroute2.netlink.ipq import NF_ACCEPT 4 | from dpkt.ip import IP 5 | 6 | ip = IPQSocket() 7 | ip.bind() 8 | try: 9 | while True: 10 | msg = ip.get()[0] 11 | print("\n") 12 | print(hexdump(msg.raw)) 13 | print(repr(IP(msg['payload']))) 14 | ip.verdict(msg['packet_id'], NF_ACCEPT) 15 | except: 16 | pass 17 | finally: 18 | ip.release() 19 | -------------------------------------------------------------------------------- /examples/iproute/ip_monitor.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Simplest example to monitor Netlink events with a Python script. 3 | ''' 4 | 5 | from pyroute2 import IPRSocket 6 | from pprint import pprint 7 | 8 | ip = IPRSocket() 9 | ip.bind() 10 | pprint(ip.get()) 11 | ip.close() 12 | -------------------------------------------------------------------------------- /examples/iproute/socketcan.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Simplest example to set CAN bitrate. 3 | ''' 4 | 5 | from pyroute2 import IPRoute 6 | 7 | with IPRoute() as ip_route: 8 | # loolkup can0 interface 9 | idx = ip_route.link_lookup(ifname='can0')[0] 10 | link = ip_route.link('get', index=idx) 11 | 12 | # bring can0 interface down. CAN settings can be set only 13 | # if the interface is down 14 | if 'state' in link[0] and link[0]['state'] == 'up': 15 | ip_route.link('set', index=idx, state='down') 16 | 17 | # set CAN birate 18 | ip_route.link('set', index=idx, kind='can', can_bittiming={'bitrate': 250000 }) 19 | 20 | # bring can0 interface up 21 | ip_route.link('set', index=idx, state='up') 22 | -------------------------------------------------------------------------------- /examples/ipset.py: -------------------------------------------------------------------------------- 1 | import socket 2 | from pyroute2.ipset import IPSet, PortRange, PortEntry 3 | 4 | ipset = IPSet() 5 | ipset.create("foo", stype="hash:ip") 6 | ipset.add("foo", "198.51.100.1", etype="ip") 7 | ipset.add("foo", "198.51.100.2", etype="ip") 8 | print(ipset.test("foo", "198.51.100.1")) # True 9 | print(ipset.test("foo", "198.51.100.10")) # False 10 | msg_list = ipset.list("foo") 11 | for msg in msg_list: 12 | for attr_data in msg.get_attr('IPSET_ATTR_ADT').get_attrs( 13 | 'IPSET_ATTR_DATA' 14 | ): 15 | for attr_ip_from in attr_data.get_attrs('IPSET_ATTR_IP_FROM'): 16 | for ipv4 in attr_ip_from.get_attrs('IPSET_ATTR_IPADDR_IPV4'): 17 | print("- " + ipv4) 18 | ipset.destroy("foo") 19 | ipset.close() 20 | 21 | 22 | ipset = IPSet() 23 | ipset.create("bar", stype="bitmap:port", bitmap_ports_range=(1000, 2000)) 24 | ipset.add("bar", 1001, etype="port") 25 | ipset.add("bar", PortRange(1500, 2000), etype="port") 26 | print(ipset.test("bar", 1600, etype="port")) # True 27 | print(ipset.test("bar", 2600, etype="port")) # False 28 | ipset.destroy("bar") 29 | ipset.close() 30 | 31 | 32 | ipset = IPSet() 33 | protocol_tcp = socket.getprotobyname("tcp") 34 | ipset.create("foobar", stype="hash:net,port") 35 | port_entry_http = PortEntry(80, protocol=protocol_tcp) 36 | ipset.add("foobar", ("198.51.100.0/24", port_entry_http), etype="net,port") 37 | print( 38 | ipset.test("foobar", ("198.51.100.1", port_entry_http), etype="ip,port") 39 | ) # True 40 | port_entry_https = PortEntry(443, protocol=protocol_tcp) 41 | print( 42 | ipset.test("foobar", ("198.51.100.1", port_entry_https), etype="ip,port") 43 | ) # False 44 | ipset.destroy("foobar") 45 | ipset.close() 46 | -------------------------------------------------------------------------------- /examples/kobject_uevent.py: -------------------------------------------------------------------------------- 1 | from pprint import pprint 2 | from pyroute2 import UeventSocket 3 | 4 | kus = UeventSocket() 5 | kus.bind() 6 | while True: 7 | pprint(kus.get()) 8 | -------------------------------------------------------------------------------- /examples/ndb/create_bond.py: -------------------------------------------------------------------------------- 1 | from pyroute2 import NDB 2 | from pyroute2.common import uifname 3 | 4 | # create unique interface names 5 | p0 = uifname() 6 | p1 = uifname() 7 | bond = uifname() 8 | 9 | with NDB() as ndb: 10 | 11 | 12 | # The same scheme works for bridge interfaces too: you 13 | # can create a bridge interface and assign ports to it 14 | # just as below. 15 | ndb.interfaces.create(kind='dummy', ifname=p0).commit() 16 | ndb.interfaces.create(kind='dummy', ifname=p1).commit() 17 | 18 | with ndb.interfaces.create(kind='bond', ifname=bond) as i: 19 | # assign two interfaces 20 | i.add_port(p0) 21 | i.add_port(p0) 22 | # make an example more scary: add IPs 23 | i.add_ip('10.251.0.1/24') 24 | i.add_ip('10.251.0.2/24') 25 | 26 | for i in (p0, p1, bond): 27 | ndb.interfaces[i].remove().commit() 28 | -------------------------------------------------------------------------------- /examples/ndb/create_interface.py: -------------------------------------------------------------------------------- 1 | from pyroute2 import NDB 2 | from pyroute2.common import uifname 3 | 4 | 5 | with NDB() as ndb: 6 | 7 | # dummy, bridge and bond interfaces are created in the 8 | # same way 9 | # 10 | # uifname() function is used here only to generate a 11 | # unique name of the interface for the regression testing, 12 | # you can pick up any name 13 | # 14 | ifname = uifname() 15 | ( 16 | ndb.interfaces.create(kind='dummy', ifname=ifname, state='up') 17 | .set('state', 'up') 18 | .set('address', '00:11:22:33:44:55') 19 | .commit() 20 | ) 21 | print(ndb.interfaces[ifname].show('json')) 22 | ( 23 | ndb.interfaces[ifname] 24 | .remove() 25 | .commit() 26 | ) 27 | -------------------------------------------------------------------------------- /examples/ndb/create_vlan.py: -------------------------------------------------------------------------------- 1 | from pyroute2 import NDB 2 | from pyroute2.common import uifname 3 | 4 | # unique interface names 5 | vlan_host = uifname() 6 | vlan_interface = uifname() 7 | 8 | with NDB() as ndb: 9 | 10 | 11 | ( 12 | ndb.interfaces.create(ifname=vlan_host, kind='dummy') 13 | .set('state', 'up') 14 | .commit() 15 | ) 16 | ( 17 | ndb.interfaces.create( 18 | ifname=vlan_interface, 19 | kind='vlan', 20 | link=ndb.interfaces[vlan_host], 21 | vlan_id=101 22 | ) 23 | .set('mtu', 1400) 24 | .set('state', 'up') 25 | .add_ip('10.251.0.1/24') 26 | .add_ip('10.251.0.2/24') 27 | .commit() 28 | ) 29 | 30 | for i in (vlan_interface, vlan_host): 31 | ndb.interfaces[i].remove().commit() 32 | -------------------------------------------------------------------------------- /examples/nftables.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from pyroute2.nftables.main import NFTables 4 | 5 | 6 | # nfgen_family 0 == inet 7 | def show_nftables(family: int = 0) -> None: 8 | nft = NFTables(nfgen_family=family) 9 | tables = nft.get_tables() 10 | chains = nft.get_chains() 11 | rules = nft.get_rules() 12 | 13 | print("Tables:") 14 | print(tables) 15 | print("\nChains:") 16 | print(chains) 17 | print("\nRules:") 18 | for rule in rules: 19 | print(rule, type(rule)) 20 | 21 | 22 | show_nftables(0) 23 | -------------------------------------------------------------------------------- /examples/nftables_sets.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | from pyroute2.netlink.nfnetlink.nftsocket import NFPROTO_IPV4 4 | from pyroute2.nftables.main import NFTables 5 | from pyroute2.nftables.main import NFTSetElem 6 | 7 | 8 | def test_ipv4_addr_set(): 9 | with NFTables(nfgen_family=NFPROTO_IPV4) as nft: 10 | nft.table("add", name="filter") 11 | my_set = nft.sets("add", table="filter", name="test0", key_type="ipv4_addr", 12 | comment="my test set", timeout=0) 13 | 14 | # With str 15 | nft.set_elems( 16 | "add", 17 | table="filter", 18 | set="test0", 19 | elements={"10.2.3.4", "10.4.3.2"}, 20 | ) 21 | 22 | # With NFTSet & NFTSetElem classes 23 | nft.set_elems( 24 | "add", 25 | set=my_set, 26 | elements={NFTSetElem(value="9.9.9.9", timeout=1000)}, 27 | ) 28 | 29 | try: 30 | assert {e.value for e in nft.set_elems("get", table="filter", set="test0")} == { 31 | "10.2.3.4", 32 | "10.4.3.2", 33 | "9.9.9.9", 34 | } 35 | assert nft.sets("get", table="filter", name="test0").comment == b"my test set" 36 | 37 | time.sleep(1.2) 38 | # timeout for elem 9.9.9.9 (1000ms) 39 | assert {e.value for e in nft.set_elems("get", table="filter", set="test0")} == { 40 | "10.2.3.4", 41 | "10.4.3.2", 42 | } 43 | finally: 44 | nft.sets("del", table="filter", name="test0") 45 | nft.table("del", name="filter") 46 | 47 | 48 | def main(): 49 | test_ipv4_addr_set() 50 | 51 | 52 | if __name__ == "__main__": 53 | main() 54 | -------------------------------------------------------------------------------- /examples/policy/policy.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import traceback 4 | from pprint import pprint 5 | from pyroute2.netlink.generic import GenericNetlinkSocket 6 | 7 | if __name__ == '__main__': 8 | try: 9 | # create protocol instance 10 | genl = GenericNetlinkSocket(ext_ack=True) 11 | 12 | # extract policy 13 | msg = genl.policy('nlctrl') 14 | 15 | # dump policy information 16 | pprint(msg) 17 | except: 18 | # if there was an error, log it to the console 19 | traceback.print_exc() 20 | finally: 21 | # finally -- release the instance 22 | genl.close() 23 | -------------------------------------------------------------------------------- /examples/processes/pmonitor.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Monitor process exit 3 | ''' 4 | from pyroute2 import TaskStats 5 | from pyroute2.common import hexdump 6 | 7 | pmask = '' 8 | 9 | with open('/proc/cpuinfo', 'r') as f: 10 | for line in f.readlines(): 11 | if line.startswith('processor'): 12 | pmask += ',' + line.split()[2] 13 | pmask = pmask[1:] 14 | ts = TaskStats() 15 | ts.register_mask(pmask) 16 | msg = ts.get()[0] 17 | print(hexdump(msg.raw)) 18 | print(msg) 19 | 20 | ts.deregister_mask(pmask) 21 | ts.release() 22 | -------------------------------------------------------------------------------- /examples/processes/taskstats.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Simple taskstats sample. 3 | ''' 4 | import os 5 | from pyroute2 import TaskStats 6 | 7 | pid = os.getpid() 8 | ts = TaskStats() 9 | # bind is required in the case of generic netlink 10 | ts.bind() 11 | ret = ts.get_pid_stat(int(pid))[0] 12 | # parsed structure 13 | print(ret) 14 | ts.close() 15 | -------------------------------------------------------------------------------- /examples/pyroute2-cli/comments: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env pyroute2-cli 2 | # 3 | ! Test mixed comments, both ! and # 4 | # 5 | interfaces # ... tail comments 6 | ! 7 | # ... indented comments 8 | ! 9 | create {ifname test01, kind dummy, address 00:11:22:33:44:55} 10 | commit 11 | ! 12 | test01 13 | # 14 | show 15 | ! 16 | remove 17 | commit 18 | -------------------------------------------------------------------------------- /examples/pyroute2-cli/create_dummy: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env pyroute2-cli 2 | # 3 | # 4 | interfaces 5 | # create a dummy interface 6 | # 7 | # there the very minimal spec consists of ifname, 8 | # other properties may be set later 9 | # 10 | create {ifname test01} 11 | # 12 | # set properties 13 | kind dummy 14 | address 00:11:22:33:44:55 15 | commit 16 | # 17 | # create addresses ... 18 | ipaddr 19 | create {address 192.168.15.67, prefixlen 24} 20 | commit 21 | create {address 192.168.15.68, prefixlen 24} 22 | commit 23 | # 24 | # and remove one of them 25 | 192.168.15.68/24 26 | remove 27 | commit 28 | # 29 | # remove the interface 30 | remove 31 | commit 32 | -------------------------------------------------------------------------------- /examples/pyroute2-cli/dump_lo: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env pyroute2-cli 2 | ! 3 | ! Just dump the loopback interface. 4 | ! 5 | interfaces lo show 6 | -------------------------------------------------------------------------------- /examples/wifi/nl80211_interface_type.py: -------------------------------------------------------------------------------- 1 | import errno 2 | from pyroute2 import IW 3 | from pyroute2 import IPRoute 4 | from pyroute2.netlink.exceptions import NetlinkError 5 | 6 | # interface name to check 7 | ifname = 'lo' 8 | 9 | ip = IPRoute() 10 | iw = IW() 11 | index = ip.link_lookup(ifname=ifname)[0] 12 | try: 13 | iw.get_interface_by_ifindex(index) 14 | print("wireless interface") 15 | except NetlinkError as e: 16 | if e.code == errno.ENODEV: # 19 'No such device' 17 | print("not a wireless interface") 18 | finally: 19 | iw.close() 20 | ip.close() 21 | -------------------------------------------------------------------------------- /examples/wifi/nl80211_interfaces.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # 4 | from pyroute2.iwutil import IW 5 | 6 | iw = IW() 7 | for q in iw.get_interfaces_dump(): 8 | phyname = 'phy%i' % int(q.get_attr('NL80211_ATTR_WIPHY')) 9 | print( 10 | '%s\t%s\t%s\t%s' 11 | % ( 12 | q.get_attr('NL80211_ATTR_IFINDEX'), 13 | phyname, 14 | q.get_attr('NL80211_ATTR_IFNAME'), 15 | q.get_attr('NL80211_ATTR_MAC'), 16 | ) 17 | ) 18 | iw.close() 19 | -------------------------------------------------------------------------------- /examples/wifi/nl80211_monitor.py: -------------------------------------------------------------------------------- 1 | from pyroute2 import IW 2 | 3 | 4 | # register IW to get all the messages 5 | iw = IW(groups=0xFFF) 6 | print(iw.get()) 7 | iw.close() 8 | -------------------------------------------------------------------------------- /examples/wifi/nl80211_set_type.py: -------------------------------------------------------------------------------- 1 | import errno 2 | from pyroute2 import IW 3 | from pyroute2 import IPRoute 4 | from pyroute2.netlink.exceptions import NetlinkError 5 | from pyroute2.netlink.nl80211 import IFTYPE_NAMES 6 | 7 | # interface name to check 8 | ifname = 'wlx2' 9 | iftype = 'monitor' 10 | 11 | iw = IW() 12 | ip = IPRoute() 13 | index = ip.link_lookup(ifname=ifname)[0] 14 | try: 15 | print(f"Original type: '{iw.get_interface_type(index)}'") 16 | iw.set_interface_type(index, iftype) 17 | print(f"New state: '{iw.get_interface_type(index)}'") 18 | except NetlinkError as e: 19 | print(f"Exception : {e}") 20 | finally: 21 | iw.close() 22 | ip.close() 23 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools", "wheel"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [[tool.mypy.overrides]] 6 | module = ["pytest.*", "pytest_asyncio.*"] 7 | ignore_missing_imports = true 8 | -------------------------------------------------------------------------------- /pyroute2/bsd/README: -------------------------------------------------------------------------------- 1 | BSD platform support 2 | ==================== 3 | 4 | BSD systems have PF_ROUTE -- a protocol similar to Netlink, but 5 | with very limited functionality. Still it is possible to use it 6 | in almost the same way one uses Netlink. Almost. 7 | 8 | This module is in the very early development stage. Ye warned. 9 | 10 | Example:: 11 | 12 | from pyroute2.bsd.rtmsocket import RTMSocket 13 | 14 | rs = RTMSocket() 15 | while True: 16 | print(rs.get()) 17 | -------------------------------------------------------------------------------- /pyroute2/bsd/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/pyroute2/bsd/__init__.py -------------------------------------------------------------------------------- /pyroute2/bsd/rtmsocket/freebsd.py: -------------------------------------------------------------------------------- 1 | from pyroute2.bsd.pf_route import ( 2 | if_announcemsg, 3 | if_msg, 4 | ifa_msg, 5 | ifma_msg, 6 | rt_msg, 7 | ) 8 | 9 | RTM_ADD = 0x1 # Add Route 10 | RTM_DELETE = 0x2 # Delete Route 11 | RTM_CHANGE = 0x3 # Change Metrics or flags 12 | RTM_GET = 0x4 # Report Metrics 13 | RTM_LOSING = 0x5 # Kernel Suspects Partitioning 14 | RTM_REDIRECT = 0x6 # Told to use different route 15 | RTM_MISS = 0x7 # Lookup failed on this address 16 | RTM_LOCK = 0x8 # Fix specified metrics 17 | RTM_RESOLVE = 0xB # Req to resolve dst to LL addr 18 | RTM_NEWADDR = 0xC # Address being added to iface 19 | RTM_DELADDR = 0xD # Address being removed from iface 20 | RTM_IFINFO = 0xE # Iface going up/down etc 21 | RTM_NEWMADDR = 0xF # Mcast group membership being added to if 22 | RTM_DELMADDR = 0x10 # Mcast group membership being deleted 23 | RTM_IFANNOUNCE = 0x11 # Iface arrival/departure 24 | RTM_IEEE80211 = 0x12 # IEEE80211 wireless event 25 | 26 | 27 | class RTMSocketBase(object): 28 | msg_map = { 29 | RTM_ADD: rt_msg, 30 | RTM_DELETE: rt_msg, 31 | RTM_CHANGE: rt_msg, 32 | RTM_GET: rt_msg, 33 | RTM_LOSING: rt_msg, 34 | RTM_REDIRECT: rt_msg, 35 | RTM_MISS: rt_msg, 36 | RTM_LOCK: rt_msg, 37 | RTM_RESOLVE: rt_msg, 38 | RTM_NEWADDR: ifa_msg, 39 | RTM_DELADDR: ifa_msg, 40 | RTM_IFINFO: if_msg, 41 | RTM_NEWMADDR: ifma_msg, 42 | RTM_DELMADDR: ifma_msg, 43 | RTM_IFANNOUNCE: if_announcemsg, 44 | RTM_IEEE80211: if_announcemsg, 45 | } 46 | -------------------------------------------------------------------------------- /pyroute2/bsd/rtmsocket/openbsd.py: -------------------------------------------------------------------------------- 1 | from pyroute2.bsd.pf_route import ( 2 | bsdmsg, 3 | if_announcemsg, 4 | if_msg, 5 | ifa_msg, 6 | rt_msg, 7 | ) 8 | 9 | RTM_ADD = 0x1 # Add Route 10 | RTM_DELETE = 0x2 # Delete Route 11 | RTM_CHANGE = 0x3 # Change Metrics or flags 12 | RTM_GET = 0x4 # Report Metrics 13 | RTM_LOSING = 0x5 # Kernel Suspects Partitioning 14 | RTM_REDIRECT = 0x6 # Told to use different route 15 | RTM_MISS = 0x7 # Lookup failed on this address 16 | RTM_LOCK = 0x8 # Fix specified metrics 17 | RTM_RESOLVE = 0xB # Req to resolve dst to LL addr 18 | RTM_NEWADDR = 0xC # Address being added to iface 19 | RTM_DELADDR = 0xD # Address being removed from iface 20 | RTM_IFINFO = 0xE # Iface going up/down etc 21 | RTM_IFANNOUNCE = 0xF # Iface arrival/departure 22 | RTM_DESYNC = 0x10 # route socket buffer overflow 23 | RTM_INVALIDATE = 0x10 # Invalidate cache of L2 route 24 | RTM_BFD = 0x12 # bidirectional forwarding detection 25 | RTM_PROPOSAL = 0x13 # proposal for netconfigd 26 | 27 | 28 | class RTMSocketBase(object): 29 | msg_map = { 30 | RTM_ADD: rt_msg, 31 | RTM_DELETE: rt_msg, 32 | RTM_CHANGE: rt_msg, 33 | RTM_GET: rt_msg, 34 | RTM_LOSING: rt_msg, 35 | RTM_REDIRECT: rt_msg, 36 | RTM_MISS: rt_msg, 37 | RTM_LOCK: rt_msg, 38 | RTM_RESOLVE: rt_msg, 39 | RTM_NEWADDR: ifa_msg, 40 | RTM_DELADDR: ifa_msg, 41 | RTM_IFINFO: if_msg, 42 | RTM_IFANNOUNCE: if_announcemsg, 43 | RTM_DESYNC: bsdmsg, 44 | RTM_INVALIDATE: bsdmsg, 45 | RTM_BFD: bsdmsg, 46 | RTM_PROPOSAL: bsdmsg, 47 | } 48 | -------------------------------------------------------------------------------- /pyroute2/cli/auth/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/pyroute2/cli/auth/__init__.py -------------------------------------------------------------------------------- /pyroute2/cli/auth/auth_keystone.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | 4 | from dateutil.parser import parse as isodate 5 | from keystoneauth1 import session 6 | from keystoneauth1.identity import v3 7 | from keystoneclient.v3 import client as ksclient 8 | from keystoneclient.v3.tokens import TokenManager 9 | 10 | 11 | class OSAuthManager(object): 12 | def __init__(self, headers): 13 | # create a Keystone password object 14 | auth = v3.Password( 15 | auth_url=os.environ.get('OS_AUTH_URL'), 16 | username=os.environ.get('OS_USERNAME'), 17 | password=os.environ.get('OS_PASSWORD'), 18 | user_domain_name=(os.environ.get('OS_USER_DOMAIN_NAME')), 19 | project_id=os.environ.get('OS_PROJECT_ID'), 20 | ) 21 | # create a session object 22 | sess = session.Session(auth=auth) 23 | # create a token manager 24 | tmanager = TokenManager(ksclient.Client(session=sess)) 25 | # validate the token 26 | keystone_response = tmanager.validate(headers['X-Auth-Token']) 27 | # init attrs 28 | self.expire = isodate(keystone_response['expires_at']).timestamp() 29 | 30 | def check(self, obj, tag): 31 | if time.time() > self.expire: 32 | raise PermissionError('keystone token has been expired') 33 | return True 34 | -------------------------------------------------------------------------------- /pyroute2/cli/auth/auth_radius.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import pyrad.packet 4 | from pyrad.client import Client 5 | from pyrad.dictionary import Dictionary 6 | 7 | 8 | class RadiusAuthManager(object): 9 | def __init__(self, headers): 10 | user = headers['X-Auth-User'] 11 | password = headers['X-Auth-Password'] 12 | 13 | client = Client( 14 | server=os.environ.get('RADIUS_SERVER'), 15 | secret=os.environ.get('RADIUS_SECRET').encode('ascii'), 16 | dict=Dictionary('dictionary'), 17 | ) 18 | 19 | req = client.CreateAuthPacket( 20 | code=pyrad.packet.AccessRequest, User_Name=user 21 | ) 22 | 23 | req['User-Password'] = req.PwCrypt(password) 24 | reply = client.SendPacket(req) 25 | self.auth = reply.code 26 | 27 | def check(self, obj, tag): 28 | return self.auth == pyrad.packet.AccessAccept 29 | -------------------------------------------------------------------------------- /pyroute2/compat.py: -------------------------------------------------------------------------------- 1 | '''Compatibility with older but supported Python versions''' 2 | 3 | try: 4 | from enum import StrEnum # noqa: F401 5 | except ImportError: 6 | from enum import Enum 7 | 8 | class StrEnum(str, Enum): 9 | '''Same as enum, but members are also strings.''' 10 | 11 | 12 | try: 13 | from socket import ETHERTYPE_IP 14 | except ImportError: 15 | # ETHERTYPE_* are new in python 3.12 16 | ETHERTYPE_IP = 0x800 17 | 18 | 19 | __all__ = ('StrEnum', 'ETHERTYPE_IP') 20 | -------------------------------------------------------------------------------- /pyroute2/config/eventlet.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from pyroute2.config.asyncio import asyncio_config 4 | 5 | log = logging.getLogger(__name__) 6 | log.warning("Please use pyroute2.config.asyncio.asyncio_config") 7 | log.warning("The eventlet module will be dropped soon ") 8 | 9 | eventlet_config = asyncio_config 10 | -------------------------------------------------------------------------------- /pyroute2/config/log.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | ## 4 | # Create the main logger 5 | # 6 | # Do NOT touch the root logger -- not to break basicConfig() etc 7 | # 8 | log = logging.getLogger('pyroute2') 9 | log.setLevel(0) 10 | log.addHandler(logging.NullHandler()) 11 | 12 | 13 | def debug(*argv, **kwarg): 14 | return log.debug(*argv, **kwarg) 15 | 16 | 17 | def info(*argv, **kwarg): 18 | return log.info(*argv, **kwarg) 19 | 20 | 21 | def warning(*argv, **kwarg): 22 | return log.warning(*argv, **kwarg) 23 | 24 | 25 | def error(*argv, **kwarg): 26 | return log.error(*argv, **kwarg) 27 | 28 | 29 | def critical(*argv, **kwarg): 30 | return log.critical(*argv, **kwarg) 31 | -------------------------------------------------------------------------------- /pyroute2/decoder/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/pyroute2/decoder/__init__.py -------------------------------------------------------------------------------- /pyroute2/decoder/args.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | 3 | 4 | def parse_args(): 5 | argument_parser = argparse.ArgumentParser() 6 | argument_parser.add_argument( 7 | '-c', '--cls', help='message class to use for decoding the data' 8 | ) 9 | argument_parser.add_argument('-d', '--data', help='data dump file') 10 | argument_parser.add_argument( 11 | '-f', '--format', default='hex', help='data file format: hex, pcap' 12 | ) 13 | argument_parser.add_argument( 14 | '-m', '--match', help='match protocol family (only for pcap data)' 15 | ) 16 | argument_parser.add_argument( 17 | '-o', 18 | '--offset', 19 | help='message offset in the data', 20 | default=0, 21 | type=int, 22 | ) 23 | argument_parser.add_argument( 24 | '-k', '--key', help='key format (see struct)', default='H' 25 | ) 26 | return argument_parser.parse_args() 27 | -------------------------------------------------------------------------------- /pyroute2/dhcp/enums/__init__.py: -------------------------------------------------------------------------------- 1 | from . import bootp, dhcp # noqa: F401 2 | -------------------------------------------------------------------------------- /pyroute2/dhcp/enums/bootp.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum, IntFlag 2 | 3 | 4 | class MessageType(IntEnum): 5 | BOOTREQUEST = 1 # Client to server 6 | BOOTREPLY = 2 # Server to client 7 | 8 | 9 | class HardwareType(IntEnum): 10 | ETHERNET = 1 # Ethernet (10Mb) 11 | EXPERIMENTAL_ETHERNET = 2 12 | AMATEUR_RADIO = 3 13 | TOKEN_RING = 4 14 | FDDI = 8 15 | ATM = 19 16 | WIRELESS_IEEE_802_11 = 20 17 | 18 | 19 | class Flag(IntFlag): 20 | UNICAST = 0x0000 # Unicast response requested 21 | BROADCAST = 0x8000 # Broadcast response requested 22 | -------------------------------------------------------------------------------- /pyroute2/ethtool/__init__.py: -------------------------------------------------------------------------------- 1 | from .ethtool import Ethtool 2 | 3 | __all__ = [Ethtool] 4 | -------------------------------------------------------------------------------- /pyroute2/ext/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/pyroute2/ext/__init__.py -------------------------------------------------------------------------------- /pyroute2/ext/icmp.py: -------------------------------------------------------------------------------- 1 | from pyroute2.protocols import msg 2 | 3 | 4 | class icmpmsg(msg): 5 | fields = [('type', 'uint8'), ('code', 'uint8'), ('csum', 'be32')] 6 | 7 | 8 | class icmp_router_adv(icmpmsg): 9 | fields = icmpmsg.fields + [ 10 | ('addrs_num', 'uint8'), 11 | ('alen', 'uint8'), 12 | ('lifetime', 'be32'), 13 | ('addrs', 'routers'), 14 | ] 15 | -------------------------------------------------------------------------------- /pyroute2/fixtures/doctest.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This module only prepares the environment for doctests 3 | in `pyroute2.fixtures`. 4 | ''' 5 | 6 | from unittest.mock import MagicMock 7 | 8 | from pyroute2 import config 9 | from pyroute2.iproute.linux import AsyncIPRoute, IPRoute 10 | from pyroute2.netlink.rtnl.ifinfmsg import ifinfmsg 11 | 12 | # config setup 13 | config.mock_netlink = True 14 | config.mock_netns = True 15 | 16 | # mock modules 17 | subprocess = MagicMock() 18 | pytest = MagicMock() 19 | 20 | # mock fixtures 21 | nsname = MagicMock() 22 | test_link_ifinfmsg = ifinfmsg() 23 | async_ipr = AsyncIPRoute() 24 | sync_ipr = IPRoute() 25 | -------------------------------------------------------------------------------- /pyroute2/fixtures/plan9.py: -------------------------------------------------------------------------------- 1 | import time 2 | from collections.abc import AsyncGenerator 3 | from socket import socketpair 4 | 5 | import pytest_asyncio 6 | 7 | from pyroute2.plan9.client import Plan9ClientSocket 8 | from pyroute2.plan9.server import Plan9ServerSocket 9 | 10 | 11 | def test_time(): 12 | return time.time_ns() 13 | 14 | 15 | class AsyncPlan9Context: 16 | 17 | server = None 18 | client = None 19 | shutdown_response = None 20 | sample_data = b'Pi6raTaXuzohdu7n' 21 | 22 | def __init__(self): 23 | self.server_sock, self.client_sock = socketpair() 24 | self.server = Plan9ServerSocket(use_socket=self.server_sock) 25 | self.client = Plan9ClientSocket(use_socket=self.client_sock) 26 | self._task = None 27 | with self.server.filesystem.create('test_file') as i: 28 | i.data.write(self.sample_data) 29 | with self.server.filesystem.create('test_time') as i: 30 | i.metadata.call_on_read = True 31 | i.register_function(test_time, loader=lambda x: {}) 32 | 33 | async def ensure_session(self): 34 | self._task = await self.server.async_run() 35 | await self.client.start_session() 36 | 37 | def close(self): 38 | self._task.cancel() 39 | self.client.close() 40 | self.server.close() 41 | 42 | 43 | @pytest_asyncio.fixture 44 | async def async_p9_context() -> AsyncGenerator[AsyncPlan9Context]: 45 | ctx = AsyncPlan9Context() 46 | await ctx.ensure_session() 47 | yield ctx 48 | ctx.close() 49 | -------------------------------------------------------------------------------- /pyroute2/inotify/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/pyroute2/inotify/__init__.py -------------------------------------------------------------------------------- /pyroute2/inotify/inotify_msg.py: -------------------------------------------------------------------------------- 1 | import struct 2 | 3 | from pyroute2.netlink import nlmsg_base, nlmsg_decoder_generic 4 | 5 | 6 | class inotify_msg(nlmsg_base, nlmsg_decoder_generic): 7 | fields = ( 8 | ('wd', 'i'), 9 | ('mask', 'I'), 10 | ('cookie', 'I'), 11 | ('name_length', 'I'), 12 | ) 13 | 14 | def decode(self): 15 | super(inotify_msg, self).decode() 16 | (name,) = struct.unpack_from( 17 | '%is' % self['name_length'], self.data, self.offset + 16 18 | ) 19 | self['name'] = name.decode('utf-8').strip('\0') 20 | self.length = self['name_length'] + 16 21 | -------------------------------------------------------------------------------- /pyroute2/iproute/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import sys 3 | 4 | from pyroute2 import config 5 | from pyroute2.iproute.linux import RTNL_API, IPBatch 6 | 7 | # compatibility fix -- LNST: 8 | from pyroute2.netlink.rtnl import ( 9 | RTM_DELADDR, 10 | RTM_DELLINK, 11 | RTM_GETADDR, 12 | RTM_GETLINK, 13 | RTM_NEWADDR, 14 | RTM_NEWLINK, 15 | ) 16 | 17 | AsyncIPRoute = None 18 | if sys.platform.startswith('win'): 19 | from pyroute2.iproute.windows import ( 20 | ChaoticIPRoute, 21 | IPRoute, 22 | NetNS, 23 | RawIPRoute, 24 | ) 25 | elif sys.platform.startswith('darwin'): 26 | from pyroute2.iproute.darwin import ( 27 | ChaoticIPRoute, 28 | IPRoute, 29 | NetNS, 30 | RawIPRoute, 31 | ) 32 | elif config.uname[0][-3:] == 'BSD': 33 | from pyroute2.iproute.bsd import ChaoticIPRoute, IPRoute, NetNS, RawIPRoute 34 | else: 35 | from pyroute2.iproute.linux import ( 36 | AsyncIPRoute, 37 | ChaoticIPRoute, 38 | IPRoute, 39 | NetNS, 40 | RawIPRoute, 41 | ) 42 | 43 | classes = [ 44 | AsyncIPRoute, 45 | RTNL_API, 46 | IPBatch, 47 | IPRoute, 48 | RawIPRoute, 49 | ChaoticIPRoute, 50 | NetNS, 51 | ] 52 | 53 | constants = [ 54 | RTM_GETLINK, 55 | RTM_NEWLINK, 56 | RTM_DELLINK, 57 | RTM_GETADDR, 58 | RTM_NEWADDR, 59 | RTM_DELADDR, 60 | ] 61 | -------------------------------------------------------------------------------- /pyroute2/ndb/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/pyroute2/ndb/__init__.py -------------------------------------------------------------------------------- /pyroute2/ndb/cluster.py: -------------------------------------------------------------------------------- 1 | import json 2 | import socket 3 | 4 | from pyroute2.common import basestring 5 | 6 | from .main import NDB 7 | from .transport import Messenger, Transport 8 | 9 | 10 | def init(config): 11 | if isinstance(config, basestring): 12 | config = json.loads(config) 13 | else: 14 | config = json.load(config) 15 | hostname = config['local'].get('hostname', socket.gethostname()) 16 | messenger = Messenger( 17 | config['local']['id'], 18 | Transport(config['local']['address'], config['local']['port']), 19 | ) 20 | 21 | for target in config['local'].get('targets', []): 22 | messenger.targets.add(target) 23 | 24 | if not messenger.targets: 25 | messenger.targets.add(hostname) 26 | 27 | for peer in config.get('peers', []): 28 | messenger.add_peer(*peer) 29 | 30 | sources = config['local'].get('sources') 31 | if sources is None: 32 | sources = [{'target': hostname, 'kind': 'local'}] 33 | 34 | return NDB( 35 | log=config.get('log', 'debug'), 36 | sources=sources, 37 | localhost=sources[0]['target'], 38 | messenger=messenger, 39 | ) 40 | -------------------------------------------------------------------------------- /pyroute2/ndb/messages.py: -------------------------------------------------------------------------------- 1 | class cmsg(dict): 2 | def __init__(self, target, payload=None): 3 | self['header'] = {'target': target} 4 | self.payload = payload 5 | 6 | 7 | class cmsg_event(cmsg): 8 | pass 9 | 10 | 11 | class cmsg_failed(cmsg): 12 | pass 13 | 14 | 15 | class cmsg_sstart(cmsg): 16 | pass 17 | -------------------------------------------------------------------------------- /pyroute2/netlink/connector/__init__.py: -------------------------------------------------------------------------------- 1 | from pyroute2.netlink import NETLINK_CONNECTOR, nlmsg 2 | from pyroute2.netlink.nlsocket import NetlinkSocket 3 | 4 | 5 | class cn_msg(nlmsg): 6 | fields = ( 7 | ('idx', 'I'), 8 | ('val', 'I'), 9 | ('seq', 'I'), 10 | ('ack', 'I'), 11 | ('len', 'H'), 12 | ('flags', 'H'), 13 | ) 14 | 15 | 16 | class ConnectorSocket(NetlinkSocket): 17 | def __init__(self, fileno=None): 18 | super().__init__(NETLINK_CONNECTOR) 19 | -------------------------------------------------------------------------------- /pyroute2/netlink/coredata.py: -------------------------------------------------------------------------------- 1 | import os 2 | from dataclasses import asdict, dataclass 3 | from typing import Optional, Type, Union 4 | 5 | from pyroute2 import config 6 | from pyroute2.requests.main import RequestFilter, RequestProcessor 7 | 8 | 9 | @dataclass 10 | class CoreConfig: 11 | target: str = 'localhost' 12 | flags: int = os.O_CREAT 13 | groups: int = 0 14 | rcvsize: int = 16384 15 | netns: Optional[str] = None 16 | tag_field: str = '' 17 | address: Optional[tuple[str, int]] = None 18 | telemetry: Optional[tuple[str, int]] = None 19 | use_socket: bool = False 20 | use_event_loop: bool = False 21 | use_libc: bool = False 22 | 23 | 24 | class CoreSocketSpec: 25 | defaults: dict[str, Union[bool, int, str, None, tuple[str, ...]]] = { 26 | 'closed': False, 27 | 'compiled': None, 28 | 'uname': config.uname, 29 | } 30 | status_filters: list[Type[RequestFilter]] = [] 31 | 32 | def __init__(self, config: CoreConfig): 33 | self.config = config 34 | self.status = RequestProcessor() 35 | for flt in self.status_filters: 36 | self.status.add_filter(flt()) 37 | self.status.update(self.defaults) 38 | self.status.update(asdict(self.config)) 39 | 40 | def __setitem__(self, key, value): 41 | setattr(self.config, key, value) 42 | self.status.update(asdict(self.config)) 43 | 44 | def __getitem__(self, key): 45 | return getattr(self.config, key) 46 | 47 | def serializable(self): 48 | return not any( 49 | ( 50 | self.config.use_socket, 51 | self.config.use_event_loop, 52 | self.config.use_libc, 53 | ) 54 | ) 55 | -------------------------------------------------------------------------------- /pyroute2/netlink/event/__init__.py: -------------------------------------------------------------------------------- 1 | from pyroute2.config import kernel 2 | from pyroute2.netlink.generic import GenericNetlinkSocket 3 | 4 | 5 | class EventSocket(GenericNetlinkSocket): 6 | marshal_class = None 7 | genl_family = None 8 | 9 | def __init__(self, *args, **kwargs): 10 | GenericNetlinkSocket.__init__(self, *args, **kwargs) 11 | self.set_marshal(self.marshal_class()) 12 | if kernel[0] <= 2: 13 | self.bind(groups=0xFFFFFF) 14 | else: 15 | self.bind() 16 | for group in self.mcast_groups: 17 | self.add_membership(group) 18 | 19 | def bind(self, groups=0, **kwarg): 20 | GenericNetlinkSocket.bind( 21 | self, 22 | self.genl_family, 23 | self.marshal_class.msg_map[0], 24 | groups, 25 | None, 26 | **kwarg 27 | ) 28 | -------------------------------------------------------------------------------- /pyroute2/netlink/exceptions.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | 4 | 5 | class NetlinkError(Exception): 6 | ''' 7 | Base netlink error 8 | ''' 9 | 10 | def __init__(self, code, msg=None): 11 | msg = msg or os.strerror(code) 12 | super(NetlinkError, self).__init__(code, msg) 13 | self.code = code 14 | self.extra_code = 0 15 | 16 | 17 | class NetlinkDecodeError(Exception): 18 | ''' 19 | Base decoding error class. 20 | 21 | Incapsulates underlying error for the following analysis 22 | ''' 23 | 24 | def __init__(self, exception): 25 | self.exception = exception 26 | 27 | 28 | class NetlinkHeaderDecodeError(NetlinkDecodeError): 29 | ''' 30 | The error occured while decoding a header 31 | ''' 32 | 33 | pass 34 | 35 | 36 | class NetlinkDataDecodeError(NetlinkDecodeError): 37 | ''' 38 | The error occured while decoding the message fields 39 | ''' 40 | 41 | pass 42 | 43 | 44 | class NetlinkNLADecodeError(NetlinkDecodeError): 45 | ''' 46 | The error occured while decoding NLA chain 47 | ''' 48 | 49 | pass 50 | 51 | 52 | class IPSetError(NetlinkError): 53 | ''' 54 | Netlink error with IPSet special error codes. 55 | 56 | Messages are imported from errcode.c 57 | ''' 58 | 59 | pass 60 | 61 | 62 | class NetlinkDumpInterrupted(NetlinkError): 63 | ''' 64 | Raised when NLM_F_DUMP_INTR is set in the flags. 65 | ''' 66 | 67 | def __init__(self, code=-1, msg='dump interrupted'): 68 | super(NetlinkDumpInterrupted, self).__init__(code, msg) 69 | 70 | 71 | class SkipInode(Exception): 72 | def __init__(self, code=0, msg=None): 73 | super(SkipInode, self).__init__(code, msg) 74 | self.code = code 75 | 76 | 77 | class ChaoticException(Exception): 78 | def __init__(self): 79 | chaotic_id = str(time.time()) 80 | super(ChaoticException, self).__init__(chaotic_id) 81 | self.chaotic_id = chaotic_id 82 | -------------------------------------------------------------------------------- /pyroute2/netlink/nfnetlink/__init__.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Nfnetlink 3 | ========= 4 | 5 | The support of nfnetlink families is now at the 6 | very beginning. So there is no public exports 7 | yet, but you can review the code. Work is in 8 | progress, stay tuned. 9 | 10 | nf-queue 11 | ++++++++ 12 | 13 | Netfilter protocol for NFQUEUE iptables target. 14 | ''' 15 | 16 | from pyroute2.netlink import nlmsg 17 | 18 | NFNL_SUBSYS_NONE = 0 19 | NFNL_SUBSYS_CTNETLINK = 1 20 | NFNL_SUBSYS_CTNETLINK_EXP = 2 21 | NFNL_SUBSYS_QUEUE = 3 22 | NFNL_SUBSYS_ULOG = 4 23 | NFNL_SUBSYS_OSF = 5 24 | NFNL_SUBSYS_IPSET = 6 25 | NFNL_SUBSYS_ACCT = 7 26 | NFNL_SUBSYS_CTNETLINK_TIMEOUT = 8 27 | NFNL_SUBSYS_CTHELPER = 9 28 | NFNL_SUBSYS_NFTABLES = 10 29 | NFNL_SUBSYS_NFT_COMPAT = 11 30 | NFNL_SUBSYS_COUNT = 12 31 | 32 | # multicast group ids (for use with {add,drop}_membership) 33 | NFNLGRP_NONE = 0 34 | NFNLGRP_CONNTRACK_NEW = 1 35 | NFNLGRP_CONNTRACK_UPDATE = 2 36 | NFNLGRP_CONNTRACK_DESTROY = 3 37 | NFNLGRP_CONNTRACK_EXP_NEW = 4 38 | NFNLGRP_CONNTRACK_EXP_UPDATE = 5 39 | NFNLGRP_CONNTRACK_EXP_DESTROY = 6 40 | NFNLGRP_NFTABLES = 7 41 | NFNLGRP_ACCT_QUOTA = 8 42 | NFNLGRP_NFTRACE = 9 43 | 44 | 45 | class nfgen_msg(nlmsg): 46 | fields = (('nfgen_family', 'B'), ('version', 'B'), ('res_id', '!H')) 47 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/errmsg.py: -------------------------------------------------------------------------------- 1 | from pyroute2.netlink import nlmsg 2 | 3 | 4 | class errmsg(nlmsg): 5 | ''' 6 | Custom message type 7 | 8 | Error ersatz-message 9 | ''' 10 | 11 | fields = (('code', 'i'),) 12 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/ifinfmsg/plugins/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/pyroute2/netlink/rtnl/ifinfmsg/plugins/__init__.py -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/ifinfmsg/plugins/bond.py: -------------------------------------------------------------------------------- 1 | from pyroute2.netlink import nla 2 | 3 | 4 | class bond(nla): 5 | prefix = 'IFLA_' 6 | nla_map = ( 7 | ('IFLA_BOND_UNSPEC', 'none'), 8 | ('IFLA_BOND_MODE', 'uint8'), 9 | ('IFLA_BOND_ACTIVE_SLAVE', 'uint32'), 10 | ('IFLA_BOND_MIIMON', 'uint32'), 11 | ('IFLA_BOND_UPDELAY', 'uint32'), 12 | ('IFLA_BOND_DOWNDELAY', 'uint32'), 13 | ('IFLA_BOND_USE_CARRIER', 'uint8'), 14 | ('IFLA_BOND_ARP_INTERVAL', 'uint32'), 15 | ('IFLA_BOND_ARP_IP_TARGET', '*ipaddr'), 16 | ('IFLA_BOND_ARP_VALIDATE', 'uint32'), 17 | ('IFLA_BOND_ARP_ALL_TARGETS', 'uint32'), 18 | ('IFLA_BOND_PRIMARY', 'uint32'), 19 | ('IFLA_BOND_PRIMARY_RESELECT', 'uint8'), 20 | ('IFLA_BOND_FAIL_OVER_MAC', 'uint8'), 21 | ('IFLA_BOND_XMIT_HASH_POLICY', 'uint8'), 22 | ('IFLA_BOND_RESEND_IGMP', 'uint32'), 23 | ('IFLA_BOND_NUM_PEER_NOTIF', 'uint8'), 24 | ('IFLA_BOND_ALL_SLAVES_ACTIVE', 'uint8'), 25 | ('IFLA_BOND_MIN_LINKS', 'uint32'), 26 | ('IFLA_BOND_LP_INTERVAL', 'uint32'), 27 | ('IFLA_BOND_PACKETS_PER_SLAVE', 'uint32'), 28 | ('IFLA_BOND_AD_LACP_RATE', 'uint8'), 29 | ('IFLA_BOND_AD_SELECT', 'uint8'), 30 | ('IFLA_BOND_AD_INFO', 'ad_info'), 31 | ('IFLA_BOND_AD_ACTOR_SYS_PRIO', 'uint16'), 32 | ('IFLA_BOND_AD_USER_PORT_KEY', 'uint16'), 33 | ('IFLA_BOND_AD_ACTOR_SYSTEM', 'hex'), 34 | ('IFLA_BOND_TLB_DYNAMIC_LB', 'uint8'), 35 | ) 36 | 37 | class ad_info(nla): 38 | nla_map = ( 39 | ('IFLA_BOND_AD_INFO_UNSPEC', 'none'), 40 | ('IFLA_BOND_AD_INFO_AGGREGATOR', 'uint16'), 41 | ('IFLA_BOND_AD_INFO_NUM_PORTS', 'uint16'), 42 | ('IFLA_BOND_AD_INFO_ACTOR_KEY', 'uint16'), 43 | ('IFLA_BOND_AD_INFO_PARTNER_KEY', 'uint16'), 44 | ('IFLA_BOND_AD_INFO_PARTNER_MAC', 'l2addr'), 45 | ) 46 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/ifinfmsg/plugins/geneve.py: -------------------------------------------------------------------------------- 1 | from pyroute2.netlink import nla, nlmsg_atoms 2 | 3 | 4 | class geneve(nla): 5 | nla_map = ( 6 | ('IFLA_GENEVE_UNSPEC', 'none'), 7 | ('IFLA_GENEVE_ID', 'uint32'), 8 | ('IFLA_GENEVE_REMOTE', 'ip4addr'), 9 | ('IFLA_GENEVE_TTL', 'uint8'), 10 | ('IFLA_GENEVE_TOS', 'uint8'), 11 | ('IFLA_GENEVE_PORT', 'be16'), 12 | ('IFLA_GENEVE_COLLECT_METADATA', 'flag'), 13 | ('IFLA_GENEVE_REMOTE6', 'ip6addr'), 14 | ('IFLA_GENEVE_UDP_CSUM', 'uint8'), 15 | ('IFLA_GENEVE_UDP_ZERO_CSUM6_TX', 'uint8'), 16 | ('IFLA_GENEVE_UDP_ZERO_CSUM6_RX', 'uint8'), 17 | ('IFLA_GENEVE_LABEL', 'be32'), 18 | ('IFLA_GENEVE_TTL_INHERIT', 'uint8'), 19 | ('IFLA_GENEVE_DF', 'df'), 20 | ) 21 | 22 | class df(nlmsg_atoms.uint16): 23 | value_map = {0: 'unset', 1: 'set', 2: 'inherit'} 24 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/ifinfmsg/plugins/gtp.py: -------------------------------------------------------------------------------- 1 | from pyroute2.netlink import nla 2 | 3 | 4 | class gtp(nla): 5 | nla_map = ( 6 | ('IFLA_GTP_UNSPEC', 'none'), 7 | ('IFLA_GTP_FD0', 'uint32'), 8 | ('IFLA_GTP_FD1', 'uint32'), 9 | ('IFLA_GTP_PDP_HASHSIZE', 'uint32'), 10 | ) 11 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/ifinfmsg/plugins/ipoib.py: -------------------------------------------------------------------------------- 1 | from pyroute2.netlink import nla, nlmsg_atoms 2 | 3 | 4 | class ipoib(nla): 5 | prefix = 'IFLA_IPOIB_' 6 | 7 | nla_map = ( 8 | ('IFLA_IPOIB_UNSPEC', 'none'), 9 | ('IFLA_IPOIB_PKEY', 'uint16'), 10 | ('IFLA_IPOIB_MODE', 'mode'), 11 | ('IFLA_IPOIB_UMCAST', 'uint16'), 12 | ) 13 | 14 | class mode(nlmsg_atoms.uint16): 15 | value_map = {0: 'datagram', 1: 'connected'} 16 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/ifinfmsg/plugins/ipvlan.py: -------------------------------------------------------------------------------- 1 | from pyroute2.netlink import nla 2 | 3 | 4 | class ipvlan(nla): 5 | prefix = 'IFLA_' 6 | nla_map = (('IFLA_IPVLAN_UNSPEC', 'none'), ('IFLA_IPVLAN_MODE', 'uint16')) 7 | 8 | modes = { 9 | 0: 'IPVLAN_MODE_L2', 10 | 1: 'IPVLAN_MODE_L3', 11 | 'IPVLAN_MODE_L2': 0, 12 | 'IPVLAN_MODE_L3': 1, 13 | } 14 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/ifinfmsg/plugins/team.py: -------------------------------------------------------------------------------- 1 | from pyroute2.netlink import nla 2 | 3 | 4 | class team(nla): 5 | prefix = 'IFLA_' 6 | 7 | nla_map = (('IFLA_TEAM_UNSPEC', 'none'), ('IFLA_TEAM_CONFIG', 'asciiz')) 8 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/ifinfmsg/plugins/tun.py: -------------------------------------------------------------------------------- 1 | from pyroute2.netlink import nla 2 | 3 | 4 | class tun(nla): 5 | prefix = 'IFLA_' 6 | nla_map = ( 7 | ('IFLA_TUN_UNSPEC', 'none'), 8 | ('IFLA_TUN_OWNER', 'uint32'), 9 | ('IFLA_TUN_GROUP', 'uint32'), 10 | ('IFLA_TUN_TYPE', 'uint8'), 11 | ('IFLA_TUN_PI', 'uint8'), 12 | ('IFLA_TUN_VNET_HDR', 'uint8'), 13 | ('IFLA_TUN_PERSIST', 'uint8'), 14 | ('IFLA_TUN_MULTI_QUEUE', 'uint8'), 15 | ('IFLA_TUN_NUM_QUEUES', 'uint32'), 16 | ('IFLA_TUN_NUM_DISABLED_QUEUES', 'uint32'), 17 | ) 18 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/ifinfmsg/plugins/tuntap.py: -------------------------------------------------------------------------------- 1 | from pyroute2.netlink import nla 2 | 3 | 4 | class tuntap(nla): 5 | ''' 6 | Fake data type 7 | ''' 8 | 9 | prefix = 'IFTUN_' 10 | nla_map = ( 11 | ('IFTUN_UNSPEC', 'none'), 12 | ('IFTUN_MODE', 'asciiz'), 13 | ('IFTUN_UID', 'uint32'), 14 | ('IFTUN_GID', 'uint32'), 15 | ('IFTUN_IFR', 'flags'), 16 | ) 17 | 18 | class flags(nla): 19 | fields = ( 20 | ('no_pi', 'B'), 21 | ('one_queue', 'B'), 22 | ('vnet_hdr', 'B'), 23 | ('tun_excl', 'B'), 24 | ('multi_queue', 'B'), 25 | ('persist', 'B'), 26 | ('nofilter', 'B'), 27 | ) 28 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/ifinfmsg/plugins/vlan.py: -------------------------------------------------------------------------------- 1 | from pyroute2.netlink import nla 2 | 3 | flags = {'reorder_hdr': 0x1, 'gvrp': 0x2, 'loose_binding': 0x4, 'mvrp': 0x8} 4 | 5 | 6 | class vlan(nla): 7 | prefix = 'IFLA_' 8 | 9 | nla_map = ( 10 | ('IFLA_VLAN_UNSPEC', 'none'), 11 | ('IFLA_VLAN_ID', 'uint16'), 12 | ('IFLA_VLAN_FLAGS', 'vlan_flags'), 13 | ('IFLA_VLAN_EGRESS_QOS', 'qos'), 14 | ('IFLA_VLAN_INGRESS_QOS', 'qos'), 15 | ('IFLA_VLAN_PROTOCOL', 'be16'), 16 | ) 17 | 18 | class vlan_flags(nla): 19 | fields = (('flags', 'I'), ('mask', 'I')) 20 | 21 | class qos(nla): 22 | prefix = 'IFLA_' 23 | 24 | nla_map = ( 25 | ('IFLA_VLAN_QOS_UNSPEC', 'none'), 26 | ('IFLA_VLAN_QOS_MAPPING', 'qos_mapping'), 27 | ) 28 | 29 | class qos_mapping(nla): 30 | fields = (('from', 'I'), ('to', 'I')) 31 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/ifinfmsg/plugins/vrf.py: -------------------------------------------------------------------------------- 1 | from pyroute2.netlink import nla 2 | 3 | 4 | class vrf(nla): 5 | prefix = 'IFLA_' 6 | nla_map = (('IFLA_VRF_UNSPEC', 'none'), ('IFLA_VRF_TABLE', 'uint32')) 7 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/ifinfmsg/plugins/vti.py: -------------------------------------------------------------------------------- 1 | from pyroute2.netlink import nla 2 | 3 | 4 | class vti(nla): 5 | prefix = 'IFLA_' 6 | nla_map = ( 7 | ('IFLA_VTI_UNSPEC', 'none'), 8 | ('IFLA_VTI_LINK', 'uint32'), 9 | ('IFLA_VTI_IKEY', 'be32'), 10 | ('IFLA_VTI_OKEY', 'be32'), 11 | ('IFLA_VTI_LOCAL', 'ip4addr'), 12 | ('IFLA_VTI_REMOTE', 'ip4addr'), 13 | ) 14 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/ifinfmsg/plugins/vti6.py: -------------------------------------------------------------------------------- 1 | from pyroute2.netlink import nla 2 | 3 | 4 | class vti6(nla): 5 | prefix = 'IFLA_' 6 | nla_map = ( 7 | ('IFLA_VTI_UNSPEC', 'none'), 8 | ('IFLA_VTI_LINK', 'uint32'), 9 | ('IFLA_VTI_IKEY', 'be32'), 10 | ('IFLA_VTI_OKEY', 'be32'), 11 | ('IFLA_VTI_LOCAL', 'ip6addr'), 12 | ('IFLA_VTI_REMOTE', 'ip6addr'), 13 | ('IFLA_VTI_FWMARK', 'uint32'), 14 | ) 15 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/ifinfmsg/plugins/vxlan.py: -------------------------------------------------------------------------------- 1 | from pyroute2.netlink import nla 2 | 3 | 4 | class vxlan(nla): 5 | prefix = 'IFLA_' 6 | nla_map = ( 7 | ('IFLA_VXLAN_UNSPEC', 'none'), 8 | ('IFLA_VXLAN_ID', 'uint32'), 9 | ('IFLA_VXLAN_GROUP', 'ip4addr'), 10 | ('IFLA_VXLAN_LINK', 'uint32'), 11 | ('IFLA_VXLAN_LOCAL', 'ip4addr'), 12 | ('IFLA_VXLAN_TTL', 'uint8'), 13 | ('IFLA_VXLAN_TOS', 'uint8'), 14 | ('IFLA_VXLAN_LEARNING', 'uint8'), 15 | ('IFLA_VXLAN_AGEING', 'uint32'), 16 | ('IFLA_VXLAN_LIMIT', 'uint32'), 17 | ('IFLA_VXLAN_PORT_RANGE', 'port_range'), 18 | ('IFLA_VXLAN_PROXY', 'uint8'), 19 | ('IFLA_VXLAN_RSC', 'uint8'), 20 | ('IFLA_VXLAN_L2MISS', 'uint8'), 21 | ('IFLA_VXLAN_L3MISS', 'uint8'), 22 | ('IFLA_VXLAN_PORT', 'be16'), 23 | ('IFLA_VXLAN_GROUP6', 'ip6addr'), 24 | ('IFLA_VXLAN_LOCAL6', 'ip6addr'), 25 | ('IFLA_VXLAN_UDP_CSUM', 'uint8'), 26 | ('IFLA_VXLAN_UDP_ZERO_CSUM6_TX', 'uint8'), 27 | ('IFLA_VXLAN_UDP_ZERO_CSUM6_RX', 'uint8'), 28 | ('IFLA_VXLAN_REMCSUM_TX', 'uint8'), 29 | ('IFLA_VXLAN_REMCSUM_RX', 'uint8'), 30 | ('IFLA_VXLAN_GBP', 'flag'), 31 | ('IFLA_VXLAN_REMCSUM_NOPARTIAL', 'flag'), 32 | ('IFLA_VXLAN_COLLECT_METADATA', 'uint8'), 33 | ('IFLA_VXLAN_LABEL', 'uint32'), 34 | ('IFLA_VXLAN_GPE', 'flag'), 35 | ('IFLA_VXLAN_TTL_INHERIT', 'flag'), 36 | ('IFLA_VXLAN_DF', 'uint8'), 37 | ) 38 | 39 | class port_range(nla): 40 | fields = (('low', '>H'), ('high', '>H')) 41 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/ifinfmsg/plugins/xfrm.py: -------------------------------------------------------------------------------- 1 | from pyroute2.netlink import nla 2 | 3 | 4 | class xfrm(nla): 5 | nla_map = ( 6 | ('IFLA_XFRM_UNSPEC', 'none'), 7 | ('IFLA_XFRM_LINK', 'uint32'), 8 | ('IFLA_XFRM_IF_ID', 'uint32'), 9 | ) 10 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/nsidmsg.py: -------------------------------------------------------------------------------- 1 | from pyroute2.netlink.rtnl.rtgenmsg import rtgenmsg 2 | 3 | 4 | class nsidmsg(rtgenmsg): 5 | nla_map = ( 6 | ('NETNSA_NONE', 'none'), 7 | ('NETNSA_NSID', 'uint32'), 8 | ('NETNSA_PID', 'uint32'), 9 | ('NETNSA_FD', 'uint32'), 10 | ('NETNSA_TARGET_NSID', 'uint32'), 11 | ('NETNSA_CURRENT_NSID', 'uint32'), 12 | ) 13 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/nsinfmsg.py: -------------------------------------------------------------------------------- 1 | from pyroute2.netlink import nlmsg, nlmsg_atoms 2 | 3 | 4 | class nsinfmsg(nlmsg): 5 | ''' 6 | Fake message type to represent network namespace information. 7 | 8 | This is a prototype, the NLA layout is subject to change without 9 | notification. 10 | ''' 11 | 12 | __slots__ = () 13 | prefix = 'NSINFO_' 14 | 15 | fields = (('inode', 'I'), ('netnsid', 'I')) 16 | 17 | nla_map = ( 18 | ('NSINFO_UNSPEC', 'none'), 19 | ('NSINFO_PATH', 'string'), 20 | ('NSINFO_PEER', 'peer'), 21 | ) 22 | 23 | class peer(nlmsg_atoms.string): 24 | sql_type = None 25 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/p2pmsg.py: -------------------------------------------------------------------------------- 1 | from pyroute2.netlink import nlmsg 2 | 3 | 4 | class p2pmsg(nlmsg): 5 | ''' 6 | Fake message type to represent peer to peer connections, 7 | be it GRE or PPP 8 | ''' 9 | 10 | __slots__ = () 11 | prefix = 'P2P_' 12 | 13 | fields = (('index', 'I'), ('family', 'I')) 14 | 15 | nla_map = ( 16 | ('P2P_UNSPEC', 'none'), 17 | ('P2P_LOCAL', 'target'), 18 | ('P2P_REMOTE', 'target'), 19 | ) 20 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/rtgenmsg.py: -------------------------------------------------------------------------------- 1 | from pyroute2.netlink import nlmsg 2 | 3 | 4 | class rtgenmsg(nlmsg): 5 | fields = (('rtgen_family', 'B'), ('__pad', '3x')) 6 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/tcmsg/README.md: -------------------------------------------------------------------------------- 1 | See the API description in `sched_template.py` 2 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/tcmsg/act_bpf.py: -------------------------------------------------------------------------------- 1 | from pyroute2.netlink import nla 2 | from pyroute2.netlink.rtnl.tcmsg.common import tc_actions 3 | 4 | 5 | def fix_request(request): 6 | if 'rate' in request: 7 | del request['rate'] 8 | 9 | 10 | class options(nla): 11 | nla_map = ( 12 | ('TCA_ACT_BPF_UNSPEC', 'none'), 13 | ('TCA_ACT_BPF_TM,', 'none'), 14 | ('TCA_ACT_BPF_PARMS', 'tca_act_bpf_parms'), 15 | ('TCA_ACT_BPF_OPS_LEN', 'uint16'), 16 | ('TCA_ACT_BPF_OPS', 'hex'), 17 | ('TCA_ACT_BPF_FD', 'uint32'), 18 | ('TCA_ACT_BPF_NAME', 'asciiz'), 19 | ) 20 | 21 | class tca_act_bpf_parms(nla): 22 | fields = ( 23 | ('index', 'I'), 24 | ('capab', 'I'), 25 | ('action', 'i'), 26 | ('refcnt', 'i'), 27 | ('bindcnt', 'i'), 28 | ) 29 | 30 | 31 | def get_parameters(kwarg): 32 | ret = {'attrs': []} 33 | if 'fd' in kwarg: 34 | ret['attrs'].append(['TCA_ACT_BPF_FD', kwarg['fd']]) 35 | if 'name' in kwarg: 36 | ret['attrs'].append(['TCA_ACT_BPF_NAME', kwarg['name']]) 37 | a = tc_actions[kwarg.get('action', 'drop')] 38 | ret['attrs'].append(['TCA_ACT_BPF_PARMS', {'action': a}]) 39 | return ret 40 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/tcmsg/act_connmark.py: -------------------------------------------------------------------------------- 1 | from pyroute2.netlink import NLA_F_NESTED, nla 2 | from pyroute2.netlink.rtnl.tcmsg.common import tc_actions 3 | 4 | """ 5 | connmark - netfilter connmark retriever action 6 | see tc-connmark(8) 7 | 8 | This filter restores the connection mark into the packet mark. 9 | Connection marks are typically handled by the CONNMARK iptables module. 10 | See iptables-extensions(8). 11 | 12 | There is no mandatory parameter, but you can specify the action, which defaults 13 | to 'pipe', and the conntrack zone (see the manual). 14 | """ 15 | 16 | 17 | class options(nla): 18 | nla_flags = NLA_F_NESTED 19 | nla_map = ( 20 | ('TCA_CONNMARK_UNSPEC', 'none'), 21 | ('TCA_CONNMARK_PARMS', 'tca_connmark_parms'), 22 | ('TCA_CONNMARK_TM', 'none'), 23 | ) 24 | 25 | class tca_connmark_parms(nla): 26 | fields = ( 27 | ('index', 'I'), 28 | ('capab', 'I'), 29 | ('action', 'i'), 30 | ('refcnt', 'i'), 31 | ('bindcnt', 'i'), 32 | ('zone', 'H'), 33 | ('__padding', 'H'), # XXX is there a better way to do this ? 34 | ) 35 | 36 | 37 | def get_parameters(kwarg): 38 | ret = {'attrs': []} 39 | 40 | parms = { 41 | 'action': tc_actions[kwarg.get('action', 'pipe')], 42 | 'zone': kwarg.get('zone', 0), 43 | } 44 | 45 | ret['attrs'].append(['TCA_CONNMARK_PARMS', parms]) 46 | return ret 47 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/tcmsg/act_gact.py: -------------------------------------------------------------------------------- 1 | from pyroute2.netlink import NLA_F_NESTED, nla 2 | from pyroute2.netlink.rtnl.tcmsg.common import tc_actions 3 | 4 | 5 | class options(nla): 6 | nla_flags = NLA_F_NESTED 7 | nla_map = ( 8 | ('TCA_GACT_UNSPEC', 'none'), 9 | ('TCA_GACT_TM', 'none'), 10 | ('TCA_GACT_PARMS', 'tca_gact_parms'), 11 | ('TCA_GACT_PROB', 'none'), 12 | ) 13 | 14 | class tca_gact_parms(nla): 15 | fields = ( 16 | ('index', 'I'), 17 | ('capab', 'I'), 18 | ('action', 'i'), 19 | ('refcnt', 'i'), 20 | ('bindcnt', 'i'), 21 | ) 22 | 23 | 24 | def get_parameters(kwarg): 25 | ret = {'attrs': []} 26 | a = tc_actions[kwarg.get('action', 'drop')] 27 | ret['attrs'].append(['TCA_GACT_PARMS', {'action': a}]) 28 | return ret 29 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/tcmsg/act_mirred.py: -------------------------------------------------------------------------------- 1 | from pyroute2.netlink import NLA_F_NESTED, nla 2 | from pyroute2.netlink.rtnl.tcmsg.common import tc_actions 3 | 4 | """ 5 | Mirred - mirror/redirect action 6 | see tc-mirred(8) 7 | 8 | Use like any other action, with the following parameters available: 9 | - direction (mandatory): ingress or egress 10 | - action (mandatory): mirror or redirect 11 | - ifindex (mandatory): destination interface for mirrored or redirected packets 12 | - index: explicit index for this action 13 | """ 14 | 15 | # see tc_mirred.h 16 | MIRRED_EACTIONS = { 17 | ("egress", "redirect"): 1, # redirect packet to egress 18 | ("egress", "mirror"): 2, # mirror packet to egress 19 | ("ingress", "redirect"): 3, # redirect packet to ingress 20 | ("ingress", "mirror"): 4, # mirror packet to ingress 21 | } 22 | 23 | 24 | class options(nla): 25 | nla_flags = NLA_F_NESTED 26 | nla_map = ( 27 | ('TCA_MIRRED_UNSPEC', 'none'), 28 | ('TCA_MIRRED_TM', 'none'), 29 | ('TCA_MIRRED_PARMS', 'tca_mirred_parms'), 30 | ) 31 | 32 | class tca_mirred_parms(nla): 33 | fields = ( 34 | ('index', 'I'), 35 | ('capab', 'I'), 36 | ('action', 'i'), 37 | ('refcnt', 'i'), 38 | ('bindcnt', 'i'), 39 | ('eaction', 'i'), 40 | ('ifindex', 'I'), 41 | ) 42 | 43 | 44 | def get_parameters(kwarg): 45 | ret = {'attrs': []} 46 | # direction, action and ifindex are mandatory 47 | parms = { 48 | 'eaction': MIRRED_EACTIONS[(kwarg['direction'], kwarg['action'])], 49 | 'ifindex': kwarg['ifindex'], 50 | } 51 | 52 | if 'index' in kwarg: 53 | parms['index'] = int(kwarg['index']) 54 | 55 | # From m_mirred.c 56 | if kwarg['action'] == 'redirect': 57 | parms['action'] = tc_actions['stolen'] 58 | else: # mirror 59 | parms['action'] = tc_actions['pipe'] 60 | 61 | ret['attrs'].append(['TCA_MIRRED_PARMS', parms]) 62 | return ret 63 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/tcmsg/act_vlan.py: -------------------------------------------------------------------------------- 1 | from socket import htons 2 | 3 | from pyroute2.netlink import nla 4 | from pyroute2.netlink.rtnl.tcmsg.common import tc_actions 5 | 6 | v_actions = {'pop': 1, 'push': 2, 'modify': 3} 7 | 8 | 9 | class options(nla): 10 | nla_map = ( 11 | ('TCA_VLAN_UNSPEC', 'none'), 12 | ('TCA_VLAN_TM', 'none'), 13 | ('TCA_VLAN_PARMS', 'tca_vlan_parms'), 14 | ('TCA_VLAN_PUSH_VLAN_ID', 'uint16'), 15 | ('TCA_VLAN_PUSH_VLAN_PROTOCOL', 'uint16'), 16 | ('TCA_VLAN_PAD', 'none'), 17 | ('TCA_VLAN_PUSH_VLAN_PRIORITY', 'uint8'), 18 | ) 19 | 20 | class tca_vlan_parms(nla): 21 | fields = ( 22 | ('index', 'I'), 23 | ('capab', 'I'), 24 | ('action', 'i'), 25 | ('refcnt', 'i'), 26 | ('bindcnt', 'i'), 27 | ('v_action', 'i'), 28 | ) 29 | 30 | 31 | def get_parameters(kwarg): 32 | ret = {'attrs': []} 33 | parms = {'v_action': v_actions[kwarg['v_action']]} 34 | parms['action'] = tc_actions[kwarg.get('action', 'pipe')] 35 | ret['attrs'].append(['TCA_VLAN_PARMS', parms]) 36 | # Vlan id compulsory for "push" and "modify" 37 | if kwarg['v_action'] in ['push', 'modify']: 38 | ret['attrs'].append(['TCA_VLAN_PUSH_VLAN_ID', kwarg['id']]) 39 | if 'priority' in kwarg: 40 | ret['attrs'].append(['TCA_VLAN_PUSH_VLAN_PRIORITY', kwarg['priority']]) 41 | if kwarg.get('protocol', '802.1Q') == '802.1ad': 42 | ret['attrs'].append(['TCA_VLAN_PUSH_VLAN_PROTOCOL', htons(0x88A8)]) 43 | else: 44 | ret['attrs'].append(['TCA_VLAN_PUSH_VLAN_PROTOCOL', htons(0x8100)]) 45 | return ret 46 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/tcmsg/cls_fw.py: -------------------------------------------------------------------------------- 1 | from socket import htons 2 | 3 | from pyroute2 import protocols 4 | from pyroute2.netlink import nla 5 | from pyroute2.netlink.rtnl.tcmsg.act_police import ( 6 | get_parameters as ap_parameters, 7 | ) 8 | from pyroute2.netlink.rtnl.tcmsg.act_police import nla_plus_police 9 | from pyroute2.netlink.rtnl.tcmsg.common_act import get_tca_action, tca_act_prio 10 | 11 | 12 | def fix_request(request): 13 | if 'rate' in request: 14 | del request['rate'] 15 | request['info'] = htons( 16 | request.get('protocol', protocols.ETH_P_ALL) & 0xFFFF 17 | ) | ((request.get('prio', 0) << 16) & 0xFFFF0000) 18 | 19 | 20 | def get_parameters(kwarg): 21 | ret = {'attrs': []} 22 | attrs_map = ( 23 | ('classid', 'TCA_FW_CLASSID'), 24 | # ('police', 'TCA_FW_POLICE'), 25 | # Handled in ap_parameters 26 | ('indev', 'TCA_FW_INDEV'), 27 | ('mask', 'TCA_FW_MASK'), 28 | ) 29 | 30 | if kwarg.get('rate'): 31 | ret['attrs'].append(['TCA_FW_POLICE', ap_parameters(kwarg)]) 32 | 33 | if kwarg.get('action'): 34 | ret['attrs'].append(['TCA_FW_ACT', get_tca_action(kwarg)]) 35 | 36 | for k, v in attrs_map: 37 | r = kwarg.get(k, None) 38 | if r is not None: 39 | ret['attrs'].append([v, r]) 40 | 41 | return ret 42 | 43 | 44 | class options(nla, nla_plus_police): 45 | nla_map = ( 46 | ('TCA_FW_UNSPEC', 'none'), 47 | ('TCA_FW_CLASSID', 'uint32'), 48 | ('TCA_FW_POLICE', 'police'), # TODO string? 49 | ('TCA_FW_INDEV', 'hex'), # TODO string 50 | ('TCA_FW_ACT', 'tca_act_prio'), 51 | ('TCA_FW_MASK', 'uint32'), 52 | ) 53 | 54 | tca_act_prio = tca_act_prio 55 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/tcmsg/cls_matchall.py: -------------------------------------------------------------------------------- 1 | from socket import htons 2 | 3 | from pyroute2 import protocols 4 | from pyroute2.netlink import nla 5 | from pyroute2.netlink.rtnl.tcmsg.common_act import get_tca_action, tca_act_prio 6 | 7 | 8 | def fix_request(request): 9 | if 'rate' in request: 10 | del request['rate'] 11 | request['info'] = htons( 12 | request.get('protocol', protocols.ETH_P_ALL) & 0xFFFF 13 | ) | ((request.get('prio', 0) << 16) & 0xFFFF0000) 14 | 15 | 16 | def get_parameters(kwarg): 17 | ret = {'attrs': []} 18 | attrs_map = ( 19 | ('classid', 'TCA_MATCHALL_CLASSID'), 20 | ('flags', 'TCA_MATCHALL_FLAGS'), 21 | ) 22 | 23 | if kwarg.get('action'): 24 | ret['attrs'].append(['TCA_MATCHALL_ACT', get_tca_action(kwarg)]) 25 | 26 | for k, v in attrs_map: 27 | r = kwarg.get(k, None) 28 | if r is not None: 29 | ret['attrs'].append([v, r]) 30 | 31 | return ret 32 | 33 | 34 | class options(nla): 35 | nla_map = ( 36 | ('TCA_MATCHALL_UNSPEC', 'none'), 37 | ('TCA_MATCHALL_CLASSID', 'be32'), 38 | ('TCA_MATCHALL_ACT', 'tca_act_prio'), 39 | ('TCA_MATCHALL_FLAGS', 'be32'), 40 | ) 41 | 42 | tca_act_prio = tca_act_prio 43 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/tcmsg/em_ipset.py: -------------------------------------------------------------------------------- 1 | from pyroute2.netlink import nlmsg_base, nlmsg_encoder_generic 2 | 3 | # see em_ipset.c 4 | IPSET_DIM = { 5 | 'IPSET_DIM_ZERO': 0, 6 | 'IPSET_DIM_ONE': 1, 7 | 'IPSET_DIM_TWO': 2, 8 | 'IPSET_DIM_THREE': 3, 9 | 'IPSET_DIM_MAX': 6, 10 | } 11 | 12 | TCF_IPSET_MODE_DST = 0 13 | TCF_IPSET_MODE_SRC = 2 14 | 15 | 16 | def get_parameters(kwarg): 17 | ret = {'attrs': []} 18 | attrs_map = ( 19 | ('matchid', 'TCF_EM_MATCHID'), 20 | ('kind', 'TCF_EM_KIND'), 21 | ('flags', 'TCF_EM_FLAGS'), 22 | ('pad', 'TCF_EM_PAD'), 23 | ) 24 | 25 | for k, v in attrs_map: 26 | r = kwarg.get(k, None) 27 | if r is not None: 28 | ret['attrs'].append([v, r]) 29 | 30 | return ret 31 | 32 | 33 | class data(nlmsg_base, nlmsg_encoder_generic): 34 | fields = ( 35 | ('ip_set_index', 'H'), 36 | ('ip_set_dim', 'B'), 37 | ('ip_set_flags', 'B'), 38 | ) 39 | 40 | def encode(self): 41 | flags, dim = self._get_ip_set_parms() 42 | 43 | self['ip_set_index'] = self['index'] 44 | self['ip_set_dim'] = dim 45 | self['ip_set_flags'] = flags 46 | nlmsg_base.encode(self) 47 | 48 | def _get_ip_set_parms(self): 49 | flags = 0 50 | dim = 0 51 | mode = self['mode'] 52 | 53 | # Split to get dimension 54 | modes = mode.split(',') 55 | dim = len(modes) 56 | if dim > IPSET_DIM['IPSET_DIM_MAX']: 57 | raise ValueError( 58 | 'IPSet dimension could not be greater than {0}'.format( 59 | IPSET_DIM['IPSET_DIM_MAX'] 60 | ) 61 | ) 62 | 63 | for i in range(0, dim): 64 | if modes[i] == 'dst': 65 | flags |= TCF_IPSET_MODE_DST << i 66 | elif modes[i] == 'src': 67 | flags |= TCF_IPSET_MODE_SRC << i 68 | else: 69 | raise ValueError('Unknown IP set mode "{0}"'.format(modes[i])) 70 | 71 | return (flags, dim) 72 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/tcmsg/sched_clsact.py: -------------------------------------------------------------------------------- 1 | ''' 2 | clsact 3 | ++++++ 4 | 5 | The clsact qdisc provides a mechanism to attach integrated 6 | filter-action classifiers to an interface, either at ingress or egress, 7 | or both. The use case shown here is using a bpf program (implemented 8 | elsewhere) to direct the packet processing. The example also uses the 9 | direct-action feature to specify what to do with each packet (pass, 10 | drop, redirect, etc.). 11 | 12 | BPF ingress/egress example using clsact qdisc:: 13 | 14 | # open_bpf_fd is outside the scope of pyroute2 15 | #fd = open_bpf_fd() 16 | eth0 = ip.get_links(ifname="eth0")[0] 17 | ip.tc("add", "clsact", eth0) 18 | # add ingress clsact 19 | ip.tc("add-filter", "bpf", idx, ":1", fd=fd, name="myprog", 20 | parent="ffff:fff2", classid=1, direct_action=True) 21 | # add egress clsact 22 | ip.tc("add-filter", "bpf", idx, ":1", fd=fd, name="myprog", 23 | parent="ffff:fff3", classid=1, direct_action=True) 24 | 25 | ''' 26 | 27 | from pyroute2.netlink.rtnl import TC_H_CLSACT 28 | 29 | parent = TC_H_CLSACT 30 | 31 | 32 | def fix_request(request): 33 | if 'rate' in request: 34 | del request['rate'] 35 | request['handle'] = 0xFFFF0000 36 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/tcmsg/sched_codel.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from pyroute2.netlink import nla 4 | from pyroute2.netlink.rtnl import TC_H_ROOT 5 | from pyroute2.netlink.rtnl.tcmsg.common import get_time 6 | from pyroute2.netlink.rtnl.tcmsg.common import stats2 as c_stats2 7 | 8 | log = logging.getLogger(__name__) 9 | parent = TC_H_ROOT 10 | 11 | 12 | def get_parameters(kwarg): 13 | # 14 | # ACHTUNG: experimental code 15 | # 16 | # Parameters naming scheme WILL be changed in next releases 17 | # 18 | ret = {'attrs': []} 19 | transform = { 20 | 'cdl_limit': lambda x: x, 21 | 'cdl_ecn': lambda x: x, 22 | 'cdl_target': get_time, 23 | 'cdl_ce_threshold': get_time, 24 | 'cdl_interval': get_time, 25 | } 26 | for key in transform: 27 | if key in kwarg: 28 | log.warning( 29 | 'codel parameters naming will be changed ' 30 | 'in next releases (%s)' % key 31 | ) 32 | ret['attrs'].append( 33 | ['TCA_CODEL_%s' % key[4:].upper(), transform[key](kwarg[key])] 34 | ) 35 | return ret 36 | 37 | 38 | class options(nla): 39 | nla_map = ( 40 | ('TCA_CODEL_UNSPEC', 'none'), 41 | ('TCA_CODEL_TARGET', 'uint32'), 42 | ('TCA_CODEL_LIMIT', 'uint32'), 43 | ('TCA_CODEL_INTERVAL', 'uint32'), 44 | ('TCA_CODEL_ECN', 'uint32'), 45 | ('TCA_CODEL_CE_THRESHOLD', 'uint32'), 46 | ) 47 | 48 | 49 | class stats(nla): 50 | fields = ( 51 | ('maxpacket', 'I'), 52 | ('count', 'I'), 53 | ('lastcount', 'I'), 54 | ('ldelay', 'I'), 55 | ('drop_next', 'I'), 56 | ('drop_overlimit', 'I'), 57 | ('ecn_mark', 'I'), 58 | ('dropping', 'I'), 59 | ('ce_mark', 'I'), 60 | ) 61 | 62 | 63 | class stats2(c_stats2): 64 | class stats_app(stats): 65 | pass 66 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/tcmsg/sched_drr.py: -------------------------------------------------------------------------------- 1 | ''' 2 | drr 3 | +++ 4 | 5 | The qdisc doesn't accept any parameters, but the class 6 | accepts `quantum` parameter:: 7 | 8 | ip.tc('add', 'drr', interface, '1:') 9 | ip.tc('add-class', 'drr', interface, '1:10', quantum=1600) 10 | ip.tc('add-class', 'drr', interface, '1:20', quantum=1600) 11 | 12 | ''' 13 | 14 | from pyroute2.netlink import nla 15 | from pyroute2.netlink.rtnl import TC_H_ROOT 16 | from pyroute2.netlink.rtnl.tcmsg.common import stats2 as c_stats2 17 | 18 | parent = TC_H_ROOT 19 | 20 | 21 | def get_class_parameters(kwarg): 22 | return {'attrs': [['TCA_DRR_QUANTUM', kwarg.get('quantum', 0)]]} 23 | 24 | 25 | class options(nla): 26 | nla_map = (('TCA_DRR_UNSPEC', 'none'), ('TCA_DRR_QUANTUM', 'uint32')) 27 | 28 | 29 | class stats(nla): 30 | fields = (('deficit', 'I'),) 31 | 32 | 33 | class stats2(c_stats2): 34 | class stats_app(stats): 35 | pass 36 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/tcmsg/sched_ingress.py: -------------------------------------------------------------------------------- 1 | from pyroute2.netlink import nla 2 | from pyroute2.netlink.rtnl import TC_H_INGRESS 3 | 4 | parent = TC_H_INGRESS 5 | 6 | 7 | def fix_request(request): 8 | if 'rate' in request: 9 | del request['rate'] 10 | request['handle'] = 0xFFFF0000 11 | 12 | 13 | class options(nla): 14 | fields = (('value', 'I'),) 15 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/tcmsg/sched_pfifo.py: -------------------------------------------------------------------------------- 1 | from pyroute2.netlink import nla 2 | from pyroute2.netlink.rtnl import TC_H_ROOT 3 | 4 | parent = TC_H_ROOT 5 | 6 | 7 | class options(nla): 8 | fields = (('limit', 'i'),) 9 | 10 | 11 | def get_parameters(kwarg): 12 | return kwarg 13 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/tcmsg/sched_pfifo_fast.py: -------------------------------------------------------------------------------- 1 | from pyroute2.netlink import nla 2 | from pyroute2.netlink.rtnl import TC_H_ROOT 3 | 4 | parent = TC_H_ROOT 5 | 6 | 7 | class options(nla): 8 | fields = (('bands', 'i'), ('priomap', '16B')) 9 | 10 | 11 | def get_parameters(kwarg): 12 | return kwarg 13 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/tcmsg/sched_plug.py: -------------------------------------------------------------------------------- 1 | from pyroute2.netlink import nla 2 | from pyroute2.netlink.rtnl import TC_H_ROOT 3 | 4 | parent = TC_H_ROOT 5 | actions = { 6 | 'TCQ_PLUG_BUFFER': 0, 7 | 'TCQ_PLUG_RELEASE_ONE': 1, 8 | 'TCQ_PLUG_RELEASE_INDEFINITE': 2, 9 | 'TCQ_PLUG_LIMIT': 3, 10 | } 11 | 12 | 13 | def get_parameters(kwarg): 14 | return { 15 | 'action': actions.get(kwarg.get('action', 0), 0), 16 | 'limit': kwarg.get('limit', 0), 17 | } 18 | 19 | 20 | class options(nla): 21 | fields = (('action', 'i'), ('limit', 'I')) 22 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/tcmsg/sched_tbf.py: -------------------------------------------------------------------------------- 1 | from pyroute2.netlink.rtnl import TC_H_ROOT 2 | from pyroute2.netlink.rtnl.tcmsg.common import ( 3 | get_rate_parameters, 4 | nla_plus_rtab, 5 | ) 6 | 7 | parent = TC_H_ROOT 8 | 9 | 10 | def fix_request(request): 11 | if 'rate' in request: 12 | del request['rate'] 13 | 14 | 15 | def get_parameters(kwarg): 16 | parms = get_rate_parameters(kwarg) 17 | # fill parameters 18 | return {'attrs': [['TCA_TBF_PARMS', parms], ['TCA_TBF_RTAB', True]]} 19 | 20 | 21 | class options(nla_plus_rtab): 22 | nla_map = ( 23 | ('TCA_TBF_UNSPEC', 'none'), 24 | ('TCA_TBF_PARMS', 'tbf_parms'), 25 | ('TCA_TBF_RTAB', 'rtab'), 26 | ('TCA_TBF_PTAB', 'ptab'), 27 | ) 28 | 29 | class tbf_parms(nla_plus_rtab.parms): 30 | fields = ( 31 | ('rate_cell_log', 'B'), 32 | ('rate___reserved', 'B'), 33 | ('rate_overhead', 'H'), 34 | ('rate_cell_align', 'h'), 35 | ('rate_mpu', 'H'), 36 | ('rate', 'I'), 37 | ('peak_cell_log', 'B'), 38 | ('peak___reserved', 'B'), 39 | ('peak_overhead', 'H'), 40 | ('peak_cell_align', 'h'), 41 | ('peak_mpu', 'H'), 42 | ('peak', 'I'), 43 | ('limit', 'I'), 44 | ('buffer', 'I'), 45 | ('mtu', 'I'), 46 | ) 47 | -------------------------------------------------------------------------------- /pyroute2/netlink/rtnl/tcmsg/sched_template.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Template sched file. All the tcmsg plugins should be 3 | registered in `__init__.py`, see the `plugins` dict. 4 | 5 | All the methods, variables and classes are optional, 6 | but the naming scheme is fixed. 7 | ''' 8 | 9 | from pyroute2.netlink import nla 10 | from pyroute2.netlink.rtnl import TC_H_ROOT 11 | from pyroute2.netlink.rtnl.tcmsg import common 12 | 13 | # if you define the `parent` variable, it will be used 14 | # as the default parent value if no other value is 15 | # provided in the call options 16 | parent = TC_H_ROOT 17 | 18 | 19 | def fix_request(request): 20 | ''' 21 | This method it called for all types -- classes, 22 | qdiscs and filters. Can be used to fix some request 23 | fields. 24 | ''' 25 | pass 26 | 27 | 28 | def get_parameters(kwarg): 29 | ''' 30 | Called for qdiscs and filters. Should return 31 | the structure to be embedded as the qdisc parameters 32 | (`TCA_OPTIONS`). 33 | ''' 34 | return None 35 | 36 | 37 | def get_class_parameters(kwarg): 38 | ''' 39 | The same as above, but called only for classes. 40 | ''' 41 | return None 42 | 43 | 44 | class options(nla.hex): 45 | ''' 46 | The `TCA_OPTIONS` struct, by default not decoded. 47 | ''' 48 | 49 | pass 50 | 51 | 52 | class stats(nla.hex): 53 | ''' 54 | The struct to decode `TCA_XSTATS`. 55 | ''' 56 | 57 | pass 58 | 59 | 60 | class stats2(common.stats2): 61 | ''' 62 | The struct to decode `TCA_STATS2`. 63 | ''' 64 | 65 | pass 66 | -------------------------------------------------------------------------------- /pyroute2/nftables/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/pyroute2/nftables/__init__.py -------------------------------------------------------------------------------- /pyroute2/nftables/parser/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/pyroute2/nftables/parser/__init__.py -------------------------------------------------------------------------------- /pyroute2/nslink/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/pyroute2/nslink/__init__.py -------------------------------------------------------------------------------- /pyroute2/plan9/ipc.py: -------------------------------------------------------------------------------- 1 | import collections 2 | import multiprocessing 3 | from socket import socketpair 4 | 5 | from pyroute2.netlink.nlsocket import NetlinkSocket 6 | from pyroute2.plan9.client import Plan9ClientSocket 7 | 8 | IPCSocketPair = collections.namedtuple('IPCSocketPair', ('server', 'client')) 9 | 10 | 11 | class IPCSocket(NetlinkSocket): 12 | 13 | def setup_socket(self): 14 | # create socket pair 15 | sp = IPCSocketPair(*socketpair()) 16 | # start the server 17 | self.socket = sp 18 | self.p9server = multiprocessing.Process(target=self.ipc_server) 19 | self.p9server.daemon = True 20 | self.p9server.start() 21 | # create and init the client 22 | self.p9client = Plan9ClientSocket(use_socket=sp.client) 23 | self.p9client.init() 24 | return sp 25 | 26 | def ipc_server(self): 27 | raise NotImplementedError() 28 | 29 | def recv(self, buffersize, flags=0): 30 | ret = self.p9client.call( 31 | fid=self.p9client.fid('call'), 32 | fname='recv', 33 | kwarg={'buffersize': buffersize, 'flags': flags}, 34 | ) 35 | return ret['data'] 36 | 37 | def send(self, data, flags=0): 38 | return self.p9client.call( 39 | fid=self.p9client.fid('call'), 40 | fname='send', 41 | kwarg={'flags': flags}, 42 | data=data, 43 | ) 44 | 45 | def bind(self): 46 | return self.p9client.call(fid=self.p9client.fid('call'), fname='bind') 47 | 48 | def close(self): 49 | self.socket.client.close() 50 | self.socket.server.close() 51 | self.p9server.wait() 52 | -------------------------------------------------------------------------------- /pyroute2/plan9/plan9socket.py: -------------------------------------------------------------------------------- 1 | from pyroute2.netlink.core import CoreSocket 2 | from pyroute2.plan9 import Marshal9P 3 | 4 | 5 | class Plan9Socket(CoreSocket): 6 | def __init__(self, use_socket=None): 7 | super().__init__(use_socket=use_socket) 8 | self.marshal = Marshal9P() 9 | self.spec['tag_field'] = 'tag' 10 | -------------------------------------------------------------------------------- /pyroute2/requests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/pyroute2/requests/__init__.py -------------------------------------------------------------------------------- /pyroute2/requests/neighbour.py: -------------------------------------------------------------------------------- 1 | from pyroute2.common import get_address_family 2 | from pyroute2.netlink.rtnl import ndmsg 3 | 4 | from .common import Index, IPRouteFilter 5 | 6 | 7 | class NeighbourFieldFilter(Index): 8 | def set_index(self, context, value): 9 | return { 10 | 'ifindex': super(NeighbourFieldFilter, self).set_index( 11 | context, value 12 | )['index'] 13 | } 14 | 15 | def set_ifindex(self, context, value): 16 | return self.set_index(context, value) 17 | 18 | def _state(self, value): 19 | if isinstance(value, str): 20 | value = ndmsg.states_a2n(value) 21 | return {'state': value} 22 | 23 | def set_nud(self, context, value): 24 | return self._state(value) 25 | 26 | def set_state(self, context, value): 27 | return self._state(value) 28 | 29 | def set_dst(self, context, value): 30 | if value: 31 | return {'dst': value} 32 | else: 33 | return {} 34 | 35 | 36 | class NeighbourIPRouteFilter(IPRouteFilter): 37 | 38 | def finalize(self, context): 39 | if self.command not in ('dump', 'get'): 40 | if 'state' not in context: 41 | context['state'] = ndmsg.NUD_PERMANENT 42 | if 'dst' in context and 'family' not in context: 43 | context['family'] = get_address_family(context['dst']) 44 | -------------------------------------------------------------------------------- /pyroute2/requests/netns.py: -------------------------------------------------------------------------------- 1 | from .common import NLAKeyTransform 2 | 3 | 4 | class NetNSFieldFilter(NLAKeyTransform): 5 | _nla_prefix = 'NSINFO_' 6 | -------------------------------------------------------------------------------- /pyroute2/requests/probe.py: -------------------------------------------------------------------------------- 1 | from socket import AF_INET 2 | 3 | from .common import NLAKeyTransform 4 | 5 | 6 | class ProbeFieldFilter(NLAKeyTransform): 7 | _nla_prefix = 'PROBE_' 8 | 9 | def finalize(self, context): 10 | if 'family' not in context: 11 | context['family'] = AF_INET 12 | if 'proto' not in context: 13 | context['proto'] = 1 14 | if 'port' not in context: 15 | context['port'] = 0 16 | if 'dst_len' not in context: 17 | context['dst_len'] = 32 18 | if 'kind' not in context: 19 | context['kind'] = 'ping' 20 | if 'num' not in context: 21 | context['num'] = 1 22 | if 'timeout' not in context: 23 | context['timeout'] = 1 24 | -------------------------------------------------------------------------------- /pyroute2/requests/rule.py: -------------------------------------------------------------------------------- 1 | import socket 2 | 3 | from pyroute2.netlink.rtnl.fibmsg import FR_ACT_NAMES, fibmsg 4 | 5 | from .common import Index, IPRouteFilter, IPTargets, NLAKeyTransform 6 | 7 | DEFAULT_FRA_PRIORITY = 32000 8 | 9 | 10 | class RuleFieldFilter(IPTargets, Index, NLAKeyTransform): 11 | _nla_prefix = fibmsg.prefix 12 | 13 | 14 | class RuleIPRouteFilter(IPRouteFilter): 15 | 16 | def get_table(self, context, mode): 17 | table = context.get('table', 0) 18 | if mode == 'field': 19 | return table if 0 <= table <= 255 else 252 20 | return table 21 | 22 | def set_action(self, context, value): 23 | if isinstance(value, str): 24 | return { 25 | 'action': FR_ACT_NAMES.get( 26 | value, FR_ACT_NAMES.get('FR_ACT_' + value.upper(), value) 27 | ) 28 | } 29 | return {'action': value} 30 | 31 | def finalize(self, context): 32 | if self.command != 'dump': 33 | if 'family' not in context: 34 | context['family'] = socket.AF_INET 35 | if 'priority' not in context: 36 | context['priority'] = DEFAULT_FRA_PRIORITY 37 | if 'table' in context and 'action' not in context: 38 | context['action'] = 'to_tbl' 39 | for key in ('src_len', 'dst_len'): 40 | if ( 41 | context.get(key, None) is None 42 | and context.get(key[:3], None) is not None 43 | ): 44 | context[key] = {socket.AF_INET6: 128, socket.AF_INET: 32}[ 45 | context['family'] 46 | ] 47 | -------------------------------------------------------------------------------- /pyroute2/statsd.py: -------------------------------------------------------------------------------- 1 | import ctypes 2 | import os 3 | import socket 4 | from typing import Literal, Optional, Union 5 | 6 | from pyroute2 import netns 7 | from pyroute2.netlink.coredata import CoreConfig, CoreSocketSpec 8 | 9 | metric_type = Literal['c', 'g', 'ms'] 10 | 11 | 12 | class StatsDClientSocket(socket.socket): 13 | '''StatsD client.''' 14 | 15 | def __init__( 16 | self, 17 | address: Optional[tuple[str, int]] = None, 18 | use_socket: Optional[socket.socket] = None, 19 | flags: int = os.O_CREAT, 20 | libc: Optional[ctypes.CDLL] = None, 21 | ): 22 | self.spec = CoreSocketSpec( 23 | CoreConfig( 24 | netns=None, address=address, use_socket=use_socket is not None 25 | ) 26 | ) 27 | self.status = self.spec.status 28 | self.buffer: str = '' 29 | if use_socket is not None: 30 | fd = use_socket.fileno() 31 | else: 32 | prime = netns.create_socket( 33 | self.spec['netns'], socket.AF_INET, socket.SOCK_DGRAM 34 | ) 35 | fd = os.dup(prime.fileno()) 36 | prime.close() 37 | super().__init__(fileno=fd) 38 | 39 | def __enter__(self): 40 | return self 41 | 42 | def __exit__(self, exc_type, exc_value, traceback): 43 | self.close() 44 | 45 | def commit(self): 46 | self.sendto(self.buffer.encode(), self.spec['address']) 47 | self.buffer = '' 48 | 49 | def put( 50 | self, name: str, value: Union[int, str], kind: metric_type 51 | ) -> None: 52 | self.buffer += f'{name}:{value}|{kind}\n' 53 | 54 | def incr(self, name: str, value: int = 1) -> None: 55 | self.put(name, value, 'c') 56 | self.commit() 57 | 58 | def gauge(self, name: str, value: int) -> None: 59 | self.put(name, value, 'g') 60 | self.commit() 61 | 62 | def timing(self, name: str, value: int) -> None: 63 | self.put(name, value, 'ms') 64 | self.commit() 65 | -------------------------------------------------------------------------------- /requirements.dev.txt: -------------------------------------------------------------------------------- 1 | build 2 | twine 3 | flake8 4 | netaddr 5 | pytest 6 | pytest-asyncio==0.26.0 7 | pytest-timeout 8 | pre-commit 9 | findimports 10 | -------------------------------------------------------------------------------- /requirements.docs.txt: -------------------------------------------------------------------------------- 1 | build 2 | twine 3 | aafigure 4 | sphinx==6.2.0 5 | sphinx-code-include 6 | pre-commit 7 | pytest 8 | pytest-asyncio==0.26.0 9 | docutils 10 | -------------------------------------------------------------------------------- /requirements.repo.txt: -------------------------------------------------------------------------------- 1 | nox 2 | pytest 3 | pytest-cov 4 | pytest-html 5 | pytest-timeout 6 | setuptools 7 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | name = pyroute2 3 | version = file: VERSION 4 | description = Python Netlink library 5 | long_description = file: README.rst 6 | author = Peter Saveliev 7 | author_email = peter@svinota.eu 8 | long_description_content_type = text/x-rst 9 | url = https://github.com/svinota/pyroute2 10 | license = GPL-2.0-or-later OR Apache-2.0 11 | classifiers = 12 | License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+) 13 | License :: OSI Approved :: Apache Software License 14 | Programming Language :: Python 15 | Topic :: Software Development :: Libraries :: Python Modules 16 | Topic :: System :: Networking 17 | Topic :: System :: Systems Administration 18 | Operating System :: POSIX :: Linux 19 | Intended Audience :: Developers 20 | Intended Audience :: System Administrators 21 | Intended Audience :: Telecommunications Industry 22 | Programming Language :: Python :: 3 23 | Programming Language :: Python :: 3.9 24 | Programming Language :: Python :: 3.10 25 | Programming Language :: Python :: 3.11 26 | Programming Language :: Python :: 3.12 27 | Programming Language :: Python :: 3.13 28 | Programming Language :: Python :: 3.14 29 | Development Status :: 4 - Beta 30 | 31 | [options] 32 | install_requires = 33 | win_inet_pton ; platform_system == "Windows" 34 | packages_dir = 35 | =pyroute2 36 | packages = find: 37 | 38 | [options.entry_points] 39 | console_scripts = 40 | ss2 = pyroute2.netlink.diag.ss2:run [psutil] 41 | pyroute2-cli = pyroute2.ndb.cli:run 42 | pyroute2-decoder = pyroute2.decoder.main:run 43 | pyroute2-dhcp-client = pyroute2.dhcp.cli:run 44 | pyroute2-test-platform = pyroute2.config.test_platform:run 45 | dhcp-server-detector = pyroute2.dhcp.server_detector:run 46 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup() 4 | -------------------------------------------------------------------------------- /tests/mocklib/dateutil/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/tests/mocklib/dateutil/__init__.py -------------------------------------------------------------------------------- /tests/mocklib/dateutil/parser.py: -------------------------------------------------------------------------------- 1 | from unittest import mock 2 | 3 | 4 | class parse(mock.Mock): 5 | def __init__(self, *argv, **kwarg): 6 | super().__init__(*argv, **kwarg) 7 | self.timestamp = mock.Mock(name='timestamp') 8 | self.timestamp.return_value = 3313938316 9 | -------------------------------------------------------------------------------- /tests/mocklib/keystoneauth1/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/tests/mocklib/keystoneauth1/__init__.py -------------------------------------------------------------------------------- /tests/mocklib/keystoneauth1/identity/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/tests/mocklib/keystoneauth1/identity/__init__.py -------------------------------------------------------------------------------- /tests/mocklib/keystoneauth1/identity/v3.py: -------------------------------------------------------------------------------- 1 | from unittest import mock 2 | 3 | Password = mock.Mock() 4 | -------------------------------------------------------------------------------- /tests/mocklib/keystoneauth1/session/__init__.py: -------------------------------------------------------------------------------- 1 | from unittest import mock 2 | 3 | Session = mock.Mock() 4 | -------------------------------------------------------------------------------- /tests/mocklib/keystoneclient/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/tests/mocklib/keystoneclient/__init__.py -------------------------------------------------------------------------------- /tests/mocklib/keystoneclient/v3/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/tests/mocklib/keystoneclient/v3/__init__.py -------------------------------------------------------------------------------- /tests/mocklib/keystoneclient/v3/client.py: -------------------------------------------------------------------------------- 1 | from unittest import mock 2 | 3 | Client = mock.Mock() 4 | -------------------------------------------------------------------------------- /tests/mocklib/keystoneclient/v3/tokens.py: -------------------------------------------------------------------------------- 1 | from unittest import mock 2 | 3 | 4 | class TokenManager: 5 | validate = mock.Mock(name='validate') 6 | validate.return_value = {'expires_at': '3022.07.04 00:00 CEST'} 7 | 8 | def __init__(self, *argv, **kwarg): 9 | pass 10 | -------------------------------------------------------------------------------- /tests/mocklib/pyrad/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/tests/mocklib/pyrad/__init__.py -------------------------------------------------------------------------------- /tests/mocklib/pyrad/client.py: -------------------------------------------------------------------------------- 1 | import collections 2 | from unittest import mock 3 | 4 | 5 | class Client(mock.MagicMock): 6 | def __init__(self, *argv, **kwarg): 7 | super().__init__(*argv, **kwarg) 8 | self.SendPacket = mock.Mock(name='SendPacket') 9 | self.SendPacket.return_value = collections.namedtuple( 10 | 'reply', ['code'] 11 | )(True) 12 | -------------------------------------------------------------------------------- /tests/mocklib/pyrad/dictionary.py: -------------------------------------------------------------------------------- 1 | from unittest import mock 2 | 3 | Dictionary = mock.Mock() 4 | -------------------------------------------------------------------------------- /tests/mocklib/pyrad/packet.py: -------------------------------------------------------------------------------- 1 | AccessRequest = True 2 | AccessAccept = True 3 | -------------------------------------------------------------------------------- /tests/test_ci/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from pyroute2 import config, netns 4 | 5 | config.mock_netlink = True 6 | config.mock_netns = True 7 | pytest_plugins = ["pyroute2.fixtures.iproute", "pyroute2.fixtures.plan9"] 8 | cleanup_netns_set = set() 9 | 10 | 11 | @pytest.fixture 12 | def netns_create_list(): 13 | return set([x[0][0] for x in netns.create().call_args_list if x[0]]) 14 | 15 | 16 | @pytest.fixture 17 | def netns_remove_list(): 18 | return set([x[0][0] for x in netns.remove().call_args_list if x[0]]) 19 | 20 | 21 | def check_fixture_spec_func(fixture, scope, name): 22 | spec = fixture._pytestfixturefunction 23 | return all((spec.name == name, spec.scope == scope)) 24 | 25 | 26 | @pytest.fixture 27 | def check_fixture_spec(): 28 | yield check_fixture_spec_func 29 | 30 | 31 | @pytest.fixture 32 | def cleanup_netns(): 33 | global cleanup_netns_set 34 | yield cleanup_netns_set 35 | -------------------------------------------------------------------------------- /tests/test_core/conftest.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | from collections import namedtuple 3 | 4 | import pytest 5 | 6 | from pyroute2.common import uifname 7 | 8 | NFTSetup = namedtuple('NFTSetup', ('table', 'chain')) 9 | 10 | 11 | @pytest.fixture 12 | def nft(): 13 | table = uifname() 14 | chain = uifname() 15 | subprocess.call(f'nft add table {table}'.split()) 16 | subprocess.call( 17 | f'nft add chain {table} {chain} ' 18 | f'{{ type filter hook input priority 500 ; }}'.split() 19 | ) 20 | subprocess.call( 21 | f'nft add chain {table} POSTROUTING ' 22 | f'{{ type nat hook postrouting priority 100 ; }}'.split() 23 | ) 24 | yield NFTSetup(table, chain) 25 | subprocess.call(f'nft delete table {table}'.split()) 26 | 27 | 28 | pytest_plugins = ["pyroute2.fixtures.iproute", "pyroute2.fixtures.plan9"] 29 | -------------------------------------------------------------------------------- /tests/test_core/test_check_tid.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import threading 3 | import warnings 4 | 5 | import pytest 6 | 7 | from pyroute2 import IPRoute 8 | 9 | 10 | def catch_tid_error(ipr): 11 | try: 12 | ipr._check_tid(tag='0x8241', level=logging.ERROR) 13 | except RuntimeError as e: 14 | assert '#0x8241' in e.args[0] 15 | warnings.warn('#0x8242') 16 | 17 | 18 | @pytest.mark.parametrize( 19 | 'func,tag', 20 | ( 21 | (lambda x: x.bind(), '#bind'), 22 | (lambda x: x._check_tid(tag='0x8240', level=logging.WARN), '#0x8240'), 23 | (catch_tid_error, '#0x8242'), 24 | ), 25 | ) 26 | def test_calls(func, tag): 27 | with warnings.catch_warnings(record=True) as wrec: 28 | with IPRoute() as ipr: 29 | t = threading.Thread(target=func, args=[ipr]) 30 | t.start() 31 | t.join() 32 | assert len(wrec) == 1 33 | assert tag in wrec[0].message.args[0] 34 | -------------------------------------------------------------------------------- /tests/test_core/test_ipr/test_addr_async.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | import pytest 4 | from net_tools import address_exists 5 | 6 | ip4v6 = re.compile('^[.:0-9a-f]*$') 7 | 8 | 9 | @pytest.mark.asyncio 10 | async def test_addr_dump(async_ipr): 11 | async for addr in await async_ipr.addr('dump'): 12 | index = addr.get('index') 13 | address = addr.get('address', '') 14 | prefixlen = addr.get('prefixlen') 15 | assert index > 0 16 | assert ip4v6.match(address) 17 | assert prefixlen > 0 18 | 19 | 20 | @pytest.mark.asyncio 21 | async def test_addr_add(async_ipr, test_link_ifname, test_link_index, nsname): 22 | await async_ipr.addr( 23 | 'add', index=test_link_index, address='192.168.145.150', prefixlen=24 24 | ) 25 | assert address_exists('192.168.145.150', test_link_ifname, netns=nsname) 26 | 27 | 28 | @pytest.mark.parametrize( 29 | 'request_info,assert_info', 30 | ( 31 | ({'preferred': 99}, {'preferred': 99}), 32 | ({'preferred_lft': 109}, {'preferred': 109}), 33 | ({'valid': 119, 'preferred': 100}, {'valid': 119}), 34 | ({'valid_lft': 129, 'preferred': 100}, {'valid': 129}), 35 | ), 36 | ) 37 | @pytest.mark.asyncio 38 | async def test_addr_cacheinfo( 39 | async_ipr, 40 | test_link_ifname, 41 | test_link_index, 42 | nsname, 43 | request_info, 44 | assert_info, 45 | ): 46 | await async_ipr.addr( 47 | 'add', 48 | index=test_link_index, 49 | address='2001:db8::5678', 50 | mask=128, 51 | **request_info 52 | ) 53 | assert address_exists('2001:db8::5678', netns=nsname, **assert_info) 54 | -------------------------------------------------------------------------------- /tests/test_core/test_ipr/test_addr_sync.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | import pytest 4 | from net_tools import address_exists 5 | 6 | ip4v6 = re.compile('^[.:0-9a-f]*$') 7 | 8 | 9 | def test_addr_dump(sync_ipr): 10 | for addr in sync_ipr.addr('dump'): 11 | index = addr.get('index') 12 | address = addr.get('address', '') 13 | prefixlen = addr.get('prefixlen') 14 | assert index > 0 15 | assert ip4v6.match(address) 16 | assert prefixlen > 0 17 | 18 | 19 | def test_addr_add(sync_ipr, test_link_ifname, test_link_index, nsname): 20 | sync_ipr.addr( 21 | 'add', index=test_link_index, address='192.168.145.150', prefixlen=24 22 | ) 23 | assert address_exists('192.168.145.150', test_link_ifname, netns=nsname) 24 | 25 | 26 | @pytest.mark.parametrize( 27 | 'request_info,assert_info', 28 | ( 29 | ({'preferred': 99}, {'preferred': 99}), 30 | ({'preferred_lft': 109}, {'preferred': 109}), 31 | ({'valid': 119, 'preferred': 100}, {'valid': 119}), 32 | ({'valid_lft': 129, 'preferred': 100}, {'valid': 129}), 33 | ), 34 | ) 35 | def test_addr_cacheinfo( 36 | sync_ipr, 37 | test_link_ifname, 38 | test_link_index, 39 | nsname, 40 | request_info, 41 | assert_info, 42 | ): 43 | sync_ipr.addr( 44 | 'add', 45 | index=test_link_index, 46 | address='2001:db8::5678', 47 | mask=128, 48 | **request_info 49 | ) 50 | assert address_exists('2001:db8::5678', netns=nsname, **assert_info) 51 | -------------------------------------------------------------------------------- /tests/test_core/test_ipr/test_link_async.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from net_tools import interface_exists 3 | 4 | 5 | @pytest.mark.asyncio 6 | async def test_link_dump(async_ipr): 7 | async for link in await async_ipr.link('dump'): 8 | assert link.get('index') > 0 9 | assert 1 < len(link.get('ifname')) < 16 10 | 11 | 12 | @pytest.mark.asyncio 13 | async def test_link_add(async_ipr, tmp_link_ifname, nsname): 14 | await async_ipr.link( 15 | 'add', ifname=tmp_link_ifname, kind='dummy', state='up' 16 | ) 17 | assert interface_exists(tmp_link_ifname, netns=nsname) 18 | 19 | 20 | @pytest.mark.asyncio 21 | async def test_link_get(async_ipr, test_link_ifname): 22 | (link,) = await async_ipr.link('get', ifname=test_link_ifname) 23 | assert link.get('state') == 'up' 24 | assert link.get('index') > 1 25 | assert link.get('ifname') == test_link_ifname 26 | assert link.get(('linkinfo', 'kind')) == 'dummy' 27 | 28 | 29 | @pytest.mark.asyncio 30 | async def test_link_del_by_index( 31 | async_ipr, test_link_ifname, test_link_index, nsname 32 | ): 33 | (link,) = await async_ipr.link('get', ifname=test_link_ifname) 34 | await async_ipr.link('del', index=test_link_index) 35 | assert not interface_exists(test_link_ifname, netns=nsname) 36 | 37 | 38 | @pytest.mark.asyncio 39 | async def test_link_del_by_name(async_ipr, test_link_ifname, nsname): 40 | await async_ipr.link('del', ifname=test_link_ifname) 41 | assert not interface_exists(test_link_ifname, netns=nsname) 42 | -------------------------------------------------------------------------------- /tests/test_core/test_ipr/test_link_sync.py: -------------------------------------------------------------------------------- 1 | from net_tools import interface_exists 2 | 3 | 4 | def test_link_dump(sync_ipr): 5 | for link in sync_ipr.link('dump'): 6 | assert link.get('index') > 0 7 | assert 1 < len(link.get('ifname')) < 16 8 | 9 | 10 | def test_link_add(sync_ipr, tmp_link_ifname, nsname): 11 | sync_ipr.link('add', ifname=tmp_link_ifname, kind='dummy', state='up') 12 | assert interface_exists(tmp_link_ifname, netns=nsname) 13 | 14 | 15 | def test_link_get(sync_ipr, test_link_ifname): 16 | (link,) = sync_ipr.link('get', ifname=test_link_ifname) 17 | assert link.get('state') == 'up' 18 | assert link.get('index') > 1 19 | assert link.get('ifname') == test_link_ifname 20 | assert link.get(('linkinfo', 'kind')) == 'dummy' 21 | 22 | 23 | def test_link_del_by_index( 24 | sync_ipr, test_link_ifname, test_link_index, nsname 25 | ): 26 | (link,) = sync_ipr.link('get', ifname=test_link_ifname) 27 | sync_ipr.link('del', index=test_link_index) 28 | assert not interface_exists(test_link_ifname, netns=nsname) 29 | 30 | 31 | def test_link_del_by_name(sync_ipr, test_link_ifname, nsname): 32 | sync_ipr.link('del', ifname=test_link_ifname) 33 | assert not interface_exists(test_link_ifname, netns=nsname) 34 | -------------------------------------------------------------------------------- /tests/test_core/test_ipr/test_route_async.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from pyroute2 import AsyncIPRoute 4 | 5 | 6 | @pytest.mark.parametrize( 7 | "command,kwarg", 8 | [ 9 | ("dump", {"table": 255}), 10 | ("show", {"table": 255}), 11 | ("dump", {"match": {"table": 255}}), 12 | ("show", {"match": {"table": 255}}), 13 | ], 14 | ) 15 | @pytest.mark.asyncio 16 | async def test_route_filter(async_ipr, command, kwarg): 17 | assert set( 18 | [ 19 | route.get('table') 20 | async for route in await async_ipr.route(command, **kwarg) 21 | ] 22 | ) == set([255]) 23 | 24 | 25 | @pytest.mark.parametrize( 26 | "command,kwarg", 27 | [ 28 | ("dump", {"table": 255, "family": 1}), 29 | ("show", {"table": 255, "family": 1}), 30 | ], 31 | ) 32 | @pytest.mark.asyncio 33 | async def test_route_filter_strict(command, kwarg): 34 | async with AsyncIPRoute(strict_check=True) as ipr: 35 | assert set( 36 | [ 37 | route.get('table') 38 | async for route in await ipr.route(command, **kwarg) 39 | ] 40 | ) == set([255]) 41 | -------------------------------------------------------------------------------- /tests/test_core/test_ipr/test_route_sync.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from pyroute2 import IPRoute 4 | 5 | 6 | @pytest.mark.parametrize( 7 | "command,kwarg", 8 | [ 9 | ("dump", {"table": 255}), 10 | ("show", {"table": 255}), 11 | ("dump", {"match": {"table": 255}}), 12 | ("show", {"match": {"table": 255}}), 13 | ], 14 | ) 15 | def test_route_filter(sync_ipr, command, kwarg): 16 | assert set( 17 | [route.get('table') for route in sync_ipr.route(command, **kwarg)] 18 | ) == set([255]) 19 | 20 | 21 | @pytest.mark.parametrize( 22 | "command,kwarg", 23 | [ 24 | ("dump", {"table": 255, "family": 1}), 25 | ("show", {"table": 255, "family": 1}), 26 | ], 27 | ) 28 | def test_route_filter_strict(command, kwarg): 29 | with IPRoute(strict_check=True) as ipr: 30 | assert set( 31 | [route.get('table') for route in ipr.route(command, **kwarg)] 32 | ) == set([255]) 33 | -------------------------------------------------------------------------------- /tests/test_core/test_ipr/test_rule_sync.py: -------------------------------------------------------------------------------- 1 | from socket import AF_INET, AF_INET6 2 | 3 | import pytest 4 | from net_tools import rule_exists 5 | 6 | 7 | @pytest.mark.parametrize( 8 | 'priority,spec', 9 | [ 10 | (30313, {'table': 10}), 11 | (30314, {'table': 10, 'src': None}), 12 | (30315, {'table': 10, 'dst': None}), 13 | (30316, {'table': 10, 'dst': '127.0.0.0/24'}), 14 | (30317, {'table': 10, 'src': '127.0.0.0/24'}), 15 | ], 16 | ) 17 | @pytest.mark.parametrize( 18 | 'sync_ipr', [{'ext_ack': True, 'strict_check': True}], indirect=True 19 | ) 20 | def test_rule_strict_src(sync_ipr, priority, spec, nsname): 21 | sync_ipr.rule('add', priority=priority, **spec) 22 | assert rule_exists(priority=priority, netns=nsname) 23 | 24 | 25 | @pytest.mark.parametrize( 26 | 'priority,proto,spec', 27 | [ 28 | (20100, AF_INET, {'table': 10}), 29 | (20101, AF_INET, {'table': 10, 'fwmark': 15}), 30 | (20102, AF_INET, {'table': 10, 'fwmark': 15, 'fwmask': 20}), 31 | (20103, AF_INET, {'table': 2048, 'FRA_FWMARK': 10, 'FRA_FWMASK': 12}), 32 | (20104, AF_INET, {'table': 2048, 'src': '127.0.1.0', 'src_len': 24}), 33 | (20105, AF_INET, {'table': 2048, 'dst': '127.0.1.0', 'dst_len': 24}), 34 | (20106, AF_INET6, {'table': 5192, 'src': 'fd00::', 'src_len': 8}), 35 | (20107, AF_INET6, {'table': 5192, 'dst': 'fd00::', 'dst_len': 8}), 36 | ], 37 | ) 38 | def test_rule_add_del(sync_ipr, priority, proto, spec, nsname): 39 | sync_ipr.rule('add', priority=priority, **spec) 40 | assert rule_exists(priority=priority, proto=proto, netns=nsname) 41 | assert ( 42 | len([x for x in sync_ipr.rule('dump', priority=priority, **spec)]) == 1 43 | ) 44 | sync_ipr.rule('del', priority=priority, **spec) 45 | assert not rule_exists( 46 | priority=priority, proto=proto, netns=nsname, timeout=0.1 47 | ) 48 | -------------------------------------------------------------------------------- /tests/test_core/test_nftables/test_nftsocket.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from pyroute2 import AsyncNFTSocket, NFTSocket 4 | from pyroute2.netlink.nfnetlink import nfgen_msg 5 | from pyroute2.netlink.nfnetlink.nftsocket import ( 6 | NFT_MSG_GETCHAIN, 7 | NFT_MSG_GETTABLE, 8 | ) 9 | 10 | list_objects = pytest.mark.parametrize( 11 | 'cmd,get_field', 12 | ( 13 | (NFT_MSG_GETTABLE, lambda x: x.table), 14 | (NFT_MSG_GETCHAIN, lambda x: x.chain), 15 | ), 16 | ids=['table', 'chain'], 17 | ) 18 | 19 | 20 | @list_objects 21 | def test_list_sync(nft, cmd, get_field): 22 | with NFTSocket() as sock: 23 | objects = [ 24 | msg.get('name') for msg in sock.request_get(nfgen_msg(), cmd) 25 | ] 26 | assert get_field(nft) in objects 27 | 28 | 29 | @list_objects 30 | @pytest.mark.asyncio 31 | async def test_list_async(nft, cmd, get_field): 32 | async with AsyncNFTSocket() as sock: 33 | objects = [ 34 | msg.get('name') 35 | async for msg in await sock.request_get(nfgen_msg(), cmd) 36 | ] 37 | assert get_field(nft) in objects 38 | -------------------------------------------------------------------------------- /tests/test_core/test_plan9/test_basic.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | import pytest 4 | 5 | 6 | @pytest.mark.asyncio 7 | async def test_server_data_read(async_p9_context): 8 | fid = await async_p9_context.client.fid('test_file') 9 | response = await async_p9_context.client.read(fid) 10 | assert response['data'] == async_p9_context.sample_data 11 | 12 | 13 | @pytest.mark.asyncio 14 | async def test_server_time_read(async_p9_context): 15 | ts = time.time_ns() 16 | fid = await async_p9_context.client.fid('test_time') 17 | responses = [await async_p9_context.client.read(fid) for _ in range(5)] 18 | times = {int(x['data'].decode('utf-8')) for x in responses} 19 | assert len(times) == 5 20 | assert min(times) > ts 21 | assert max(times) < time.time_ns() 22 | 23 | 24 | @pytest.mark.asyncio 25 | async def test_server_data_write(async_p9_context): 26 | new_sample = b'aevei3PhaeGeiseh' 27 | fid = await async_p9_context.client.fid('test_file') 28 | await async_p9_context.client.write(fid, new_sample) 29 | response = await async_p9_context.client.read(fid) 30 | assert response['data'] == new_sample 31 | assert new_sample != async_p9_context.sample_data 32 | -------------------------------------------------------------------------------- /tests/test_core/test_socket_create.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | import pytest 4 | 5 | from pyroute2 import AsyncIPRoute, config, netns 6 | from pyroute2.common import uifname 7 | 8 | 9 | def fake_create(*argv, **kwarg): 10 | time.sleep(600) 11 | 12 | 13 | @pytest.mark.asyncio 14 | async def test_netns_timeout(monkeypatch): 15 | monkeypatch.setattr(config, 'default_create_socket_timeout', 1) 16 | monkeypatch.setattr(config, 'default_communicate_timeout', 0.3) 17 | monkeypatch.setattr(netns, '_create_socket_child', fake_create) 18 | 19 | ipr = AsyncIPRoute(netns=uifname()) 20 | ts_start = time.time() 21 | with pytest.raises(TimeoutError): 22 | await ipr.setup_endpoint() 23 | assert time.time() - ts_start < 2 24 | -------------------------------------------------------------------------------- /tests/test_decoder/nl0.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/tests/test_decoder/nl0.pcap -------------------------------------------------------------------------------- /tests/test_decoder/test_pcap.py: -------------------------------------------------------------------------------- 1 | import json 2 | import subprocess 3 | 4 | 5 | def test_pcap_rtnl(): 6 | decoder = subprocess.Popen( 7 | [ 8 | "pyroute2-decoder", 9 | "-c", 10 | "pyroute2/netlink/rtnl/marshal.MarshalRtnl", 11 | "-d", 12 | "test_decoder/nl0.pcap", 13 | "-m", 14 | "ll_header{family=0}", 15 | ], 16 | stdout=subprocess.PIPE, 17 | ) 18 | dump = json.loads(decoder.communicate()[0]) 19 | decoder.wait() 20 | with open("test_decoder/nl0.json", 'r') as f: 21 | ref = json.load(f) 22 | assert len(ref) == len(dump) 23 | for i in range(len(ref)): 24 | assert ref[i]["pcap header"] == dump[i]["pcap header"] 25 | assert ref[i]["message class"] == dump[i]["message class"] 26 | 27 | 28 | def test_pcap_ipvs(): 29 | decoder = subprocess.Popen( 30 | [ 31 | "pyroute2-decoder", 32 | "-c", 33 | "pyroute2/netlink/generic/ipvs.ipvsmsg", 34 | "-d", 35 | "test_decoder/nl0.pcap", 36 | "-m", 37 | ( 38 | "ll_header{family=16}" 39 | " AND data{fmt='H', offset=4, value=37}" 40 | " AND data{fmt='B', offset=16, value=1}" 41 | ), 42 | ], 43 | stdout=subprocess.PIPE, 44 | ) 45 | dump = json.loads(decoder.communicate()[0]) 46 | decoder.wait() 47 | assert len(dump) == 1 48 | assert dump[0]["data"]["cmd"] == 1 49 | assert dump[0]["data"]["header"]["type"] == 37 50 | assert dump[0]["link layer header"].find("family=16") > 0 51 | assert dump[0]["data"]["attrs"][0][0] == "IPVS_CMD_ATTR_SERVICE" 52 | -------------------------------------------------------------------------------- /tests/test_integration/conftest.py: -------------------------------------------------------------------------------- 1 | pytest_plugins = ["pyroute2.fixtures.iproute"] 2 | -------------------------------------------------------------------------------- /tests/test_integration/test_lnst.py: -------------------------------------------------------------------------------- 1 | import select 2 | 3 | import pytest 4 | 5 | from pyroute2 import IPRoute, IPRSocket 6 | from pyroute2.netlink import NLM_F_DUMP, NLM_F_REQUEST 7 | from pyroute2.netlink.rtnl import RTM_GETADDR, RTM_GETLINK 8 | 9 | 10 | @pytest.mark.parametrize( 11 | 'msg_type,dump_method,field,event', 12 | [ 13 | (RTM_GETLINK, 'link', 'ifname', 'RTM_NEWLINK'), 14 | (RTM_GETADDR, 'addr', 'address', 'RTM_NEWADDR'), 15 | ], 16 | ) 17 | def test_interface_manager_dump_link( 18 | nsname, msg_type, dump_method, field, event 19 | ): 20 | with IPRSocket(netns=nsname) as iprsock, IPRoute(netns=nsname) as ipr: 21 | 22 | # bring up loopback 23 | ipr.link('set', index=1, state='up') 24 | ipr.poll(ipr.addr, 'dump', address='127.0.0.1', timeout=1) 25 | 26 | # init dump: 27 | # InterfaceManager.request_netlink_dump() 28 | iprsock.put(None, msg_type, msg_flags=NLM_F_REQUEST | NLM_F_DUMP) 29 | 30 | # collect responses: 31 | # InterfaceManager.pull_netlink_messages_into_queue() 32 | ret = [] 33 | while True: 34 | rl, wl, xl = select.select([iprsock], [], [], 0) 35 | if not len(rl): 36 | break 37 | ret.extend(iprsock.get()) 38 | 39 | links = [x for x in getattr(ipr, dump_method)('dump')] 40 | ifnames_ipr = set([x.get(field) for x in links]) 41 | ifnames_iprsock = set( 42 | [x.get(field) for x in ret if x.get('event') == event] 43 | ) 44 | assert ifnames_iprsock == ifnames_ipr 45 | -------------------------------------------------------------------------------- /tests/test_integration/test_os_vif.py: -------------------------------------------------------------------------------- 1 | from pyroute2.common import uifname 2 | 3 | 4 | def test_impl_lookup(sync_ipr, test_link_ifname): 5 | assert len(sync_ipr.link_lookup(ifname=test_link_ifname)) == 1 6 | 7 | 8 | def test_impl_add_bridge(sync_ipr): 9 | brname = uifname() 10 | args = { 11 | 'ifname': brname, 12 | 'kind': 'bridge', 13 | 'IFLA_BR_FORWARD_DELAY': 0, 14 | 'IFLA_BR_STP_STATE': 0, 15 | 'IFLA_BR_MCAST_SNOOPING': 0, 16 | 'IFLA_BR_AGEING_TIME': 1500, 17 | } 18 | sync_ipr.link('add', **args) 19 | link = [ 20 | x 21 | for x in sync_ipr.poll(sync_ipr.link, 'dump', ifname=brname, timeout=5) 22 | ][0] 23 | assert link.get(('linkinfo', 'data', 'br_forward_delay')) == 0 24 | assert link.get(('linkinfo', 'data', 'br_stp_state')) == 0 25 | assert link.get(('linkinfo', 'data', 'br_mcast_snooping')) == 0 26 | assert link.get(('linkinfo', 'data', 'br_ageing_time')) == 1500 27 | 28 | 29 | def test_impl_add_vlan(sync_ipr, test_link_index): 30 | vname = uifname() 31 | args = { 32 | 'ifname': vname, 33 | 'kind': 'vlan', 34 | 'vlan_id': 1001, 35 | 'link': test_link_index, 36 | } 37 | sync_ipr.link('add', **args) 38 | link = [ 39 | x 40 | for x in sync_ipr.poll(sync_ipr.link, 'dump', ifname=vname, timeout=5) 41 | ][0] 42 | assert link.get(('linkinfo', 'data', 'vlan_id')) == 1001 43 | -------------------------------------------------------------------------------- /tests/test_integration/test_ovn_bgp_agent.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from pyroute2 import iproute 4 | from pyroute2.common import uifname 5 | 6 | 7 | @pytest.mark.parametrize( 8 | 'method,argv', 9 | (('get_rules', []), ('route', ['show']), ('brport', ['show'])), 10 | ) 11 | def test_iproute_call(method, argv): 12 | with iproute.IPRoute() as ip: 13 | iter(getattr(ip, method)(*argv)) 14 | 15 | 16 | @pytest.mark.parametrize( 17 | 'param,value', (('neigh_suppress', True), ('learning', False)) 18 | ) 19 | def test_brport_set( 20 | sync_ipr, ndb, test_link_index, test_link_ifname, param, value 21 | ): 22 | brname = uifname() 23 | ndb.interfaces.create(ifname=brname, kind='bridge').add_port( 24 | test_link_ifname 25 | ).commit() 26 | kwarg = {param: value} 27 | sync_ipr.brport('set', index=test_link_index, **kwarg) 28 | sync_ipr.poll( 29 | sync_ipr.brport, 'dump', index=test_link_index, timeout=5, **kwarg 30 | ) 31 | -------------------------------------------------------------------------------- /tests/test_limits/conftest.py: -------------------------------------------------------------------------------- 1 | pytest_plugins = ["pyroute2.fixtures.iproute"] 2 | -------------------------------------------------------------------------------- /tests/test_linux/pr2test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/tests/test_linux/pr2test/__init__.py -------------------------------------------------------------------------------- /tests/test_linux/pr2test/custom_link_kind/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/tests/test_linux/pr2test/custom_link_kind/__init__.py -------------------------------------------------------------------------------- /tests/test_linux/pr2test/custom_link_kind/foo.py: -------------------------------------------------------------------------------- 1 | from pyroute2.netlink import nla 2 | 3 | register_kind = 'vlan' 4 | 5 | 6 | class vlan(nla): 7 | prefix = 'IFLA_' 8 | 9 | nla_map = ( 10 | ('IFLA_FOO_UNSPEC', 'none'), 11 | ('IFLA_FOO_ID', 'uint16'), 12 | ('IFLA_FOO_FLAGS', 'vlan_flags'), 13 | ('IFLA_FOO_EGRESS_QOS', 'qos'), 14 | ('IFLA_FOO_INGRESS_QOS', 'qos'), 15 | ('IFLA_FOO_PROTOCOL', 'be16'), 16 | ) 17 | 18 | class vlan_flags(nla): 19 | fields = (('flags', 'I'), ('mask', 'I')) 20 | 21 | class qos(nla): 22 | nla_map = ( 23 | ('IFLA_VLAN_QOS_UNSPEC', 'none'), 24 | ('IFLA_VLAN_QOS_MAPPING', 'qos_mapping'), 25 | ) 26 | 27 | class qos_mapping(nla): 28 | fields = (('from', 'I'), ('to', 'I')) 29 | -------------------------------------------------------------------------------- /tests/test_linux/pr2test/marks.py: -------------------------------------------------------------------------------- 1 | import getpass 2 | 3 | import pytest 4 | 5 | 6 | def require_root(func=None): 7 | mark = pytest.mark.skipif( 8 | getpass.getuser() != 'root', reason='no root access' 9 | ) 10 | if func: 11 | return mark(func) 12 | else: 13 | return mark 14 | -------------------------------------------------------------------------------- /tests/test_linux/test_api/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/tests/test_linux/test_api/__init__.py -------------------------------------------------------------------------------- /tests/test_linux/test_devlink.py: -------------------------------------------------------------------------------- 1 | from pr2test.context_manager import skip_if_not_supported 2 | 3 | from pyroute2 import DL 4 | 5 | 6 | @skip_if_not_supported 7 | def test_list(): 8 | with DL() as dl: 9 | dls = dl.get_dump() 10 | if not dls: 11 | raise RuntimeError('no devlink devices found') 12 | 13 | assert dl.list() 14 | -------------------------------------------------------------------------------- /tests/test_linux/test_dhcp/captures/test_parser/test_android_reboot_request.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/tests/test_linux/test_dhcp/captures/test_parser/test_android_reboot_request.pcap -------------------------------------------------------------------------------- /tests/test_linux/test_dhcp/captures/test_parser/test_android_tethering_renew.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/tests/test_linux/test_dhcp/captures/test_parser/test_android_tethering_renew.pcap -------------------------------------------------------------------------------- /tests/test_linux/test_dhcp/captures/test_parser/test_decode_simple_lease_process.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/tests/test_linux/test_dhcp/captures/test_parser/test_decode_simple_lease_process.pcap -------------------------------------------------------------------------------- /tests/test_linux/test_dhcp/captures/test_parser/test_huawei_discover_option_148.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/tests/test_linux/test_dhcp/captures/test_parser/test_huawei_discover_option_148.pcap -------------------------------------------------------------------------------- /tests/test_linux/test_dhcp/captures/test_parser/test_invalid_client_id_option.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/tests/test_linux/test_dhcp/captures/test_parser/test_invalid_client_id_option.pcap -------------------------------------------------------------------------------- /tests/test_linux/test_dhcp/captures/test_parser/test_invalid_router_option.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/tests/test_linux/test_dhcp/captures/test_parser/test_invalid_router_option.pcap -------------------------------------------------------------------------------- /tests/test_linux/test_dhcp/captures/test_parser/test_netatmo_discover_request.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/tests/test_linux/test_dhcp/captures/test_parser/test_netatmo_discover_request.pcap -------------------------------------------------------------------------------- /tests/test_linux/test_dhcp/captures/test_parser/test_truncated_packet.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/tests/test_linux/test_dhcp/captures/test_parser/test_truncated_packet.pcap -------------------------------------------------------------------------------- /tests/test_linux/test_dhcp/captures/test_parser/test_washing_machine_request.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/tests/test_linux/test_dhcp/captures/test_parser/test_washing_machine_request.pcap -------------------------------------------------------------------------------- /tests/test_linux/test_dhcp/captures/test_parser/test_wii_discover.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/tests/test_linux/test_dhcp/captures/test_parser/test_wii_discover.pcap -------------------------------------------------------------------------------- /tests/test_linux/test_dhcp/captures/test_unit/test_ack_invalid_request_state.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/tests/test_linux/test_dhcp/captures/test_unit/test_ack_invalid_request_state.pcap -------------------------------------------------------------------------------- /tests/test_linux/test_dhcp/captures/test_unit/test_get_and_renew_lease.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/tests/test_linux/test_dhcp/captures/test_unit/test_get_and_renew_lease.pcap -------------------------------------------------------------------------------- /tests/test_linux/test_dhcp/captures/test_unit/test_init_reboot_nak.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/tests/test_linux/test_dhcp/captures/test_unit/test_init_reboot_nak.pcap -------------------------------------------------------------------------------- /tests/test_linux/test_dhcp/captures/test_unit/test_offer_wrong_xid.pcap: -------------------------------------------------------------------------------- 1 | test_requesting_timeout.pcap -------------------------------------------------------------------------------- /tests/test_linux/test_dhcp/captures/test_unit/test_requesting_timeout.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/tests/test_linux/test_dhcp/captures/test_unit/test_requesting_timeout.pcap -------------------------------------------------------------------------------- /tests/test_linux/test_dhcp/captures/test_unit/test_truncated_packet.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/tests/test_linux/test_dhcp/captures/test_unit/test_truncated_packet.pcap -------------------------------------------------------------------------------- /tests/test_linux/test_dhcp/captures/test_unit/test_unexpected_dhcp_message.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/tests/test_linux/test_dhcp/captures/test_unit/test_unexpected_dhcp_message.pcap -------------------------------------------------------------------------------- /tests/test_linux/test_dhcp/captures/test_unit/test_unknown_message.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/tests/test_linux/test_dhcp/captures/test_unit/test_unknown_message.pcap -------------------------------------------------------------------------------- /tests/test_linux/test_dhcp/test_encode.py: -------------------------------------------------------------------------------- 1 | from typing import Any 2 | 3 | import pytest 4 | 5 | from pyroute2.dhcp.dhcp4msg import dhcp4msg 6 | from pyroute2.dhcp.enums import dhcp 7 | 8 | 9 | @pytest.mark.parametrize( 10 | ('option_name', 'option_value'), 11 | ( 12 | ('name_server', ['1.1.1.2', '2.2.2.2']), 13 | ('lease_time', -1), 14 | ('host_name', 'some computer'), 15 | ('max_msg_size', 1500), 16 | ('subnet_mask', '255.255.255.0'), 17 | ('client_id', {'type': 1, 'key': '16:f4:cb:71:09:a1'}), 18 | ('client_id', {'type': 0, 'key': b'some-client-identifier'}), 19 | ('perform_mask_discovery', True), 20 | ('tcp_keepalive_garbage', False), 21 | ('host_name', [104, 97, 153, 104, 97]), 22 | ), 23 | ) 24 | def test_encode_decode_options(option_name: str, option_value: Any): 25 | msg = dhcp4msg( 26 | { 27 | 'options': { 28 | 'message_type': dhcp.MessageType.ACK, 29 | option_name: option_value, 30 | } 31 | } 32 | ) 33 | data = msg.encode().buf 34 | decoded_msg = dhcp4msg(buf=data).decode() 35 | assert ( 36 | decoded_msg['options'][option_name] 37 | == msg['options'][option_name] 38 | == option_value 39 | ) 40 | 41 | 42 | # TODO: test invalid client id 43 | -------------------------------------------------------------------------------- /tests/test_linux/test_diag.py: -------------------------------------------------------------------------------- 1 | from socket import AF_UNIX 2 | 3 | from pr2test.marks import require_root 4 | 5 | from pyroute2 import DiagSocket 6 | 7 | pytestmark = [require_root()] 8 | 9 | 10 | def test_basic(): 11 | sstats_set = set() 12 | pstats_set = set() 13 | sstats = None 14 | fd = None 15 | 16 | with DiagSocket() as ds: 17 | ds.bind() 18 | sstats = ds.get_sock_stats(family=AF_UNIX) 19 | for s in sstats: 20 | sstats_set.add(s['udiag_ino']) 21 | 22 | with open('/proc/net/unix') as fd: 23 | for line in fd.readlines(): 24 | line = line.split() 25 | try: 26 | pstats_set.add(int(line[6])) 27 | except ValueError: 28 | pass 29 | 30 | assert len(sstats_set - pstats_set) < 10 31 | assert len(pstats_set - sstats_set) < 10 32 | -------------------------------------------------------------------------------- /tests/test_linux/test_dquot/dquot.img.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/tests/test_linux/test_dquot/dquot.img.gz -------------------------------------------------------------------------------- /tests/test_linux/test_ethtool.py: -------------------------------------------------------------------------------- 1 | import gc 2 | import os 3 | 4 | from pyroute2 import Ethtool 5 | 6 | 7 | def get_fds(): 8 | fd = os.open(f'/proc/{os.getpid()}/fd', os.O_RDONLY) 9 | try: 10 | return set(os.listdir(fd)) - {fd} 11 | finally: 12 | os.close(fd) 13 | 14 | 15 | def _test_pipe_leak(): 16 | fds = get_fds() 17 | etht = Ethtool() 18 | etht.close() 19 | gc.collect() 20 | assert get_fds() == fds 21 | 22 | 23 | def _test_context_manager(): 24 | fds = get_fds() 25 | with Ethtool(): 26 | pass 27 | gc.collect() 28 | assert get_fds() == fds 29 | -------------------------------------------------------------------------------- /tests/test_linux/test_generic/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/tests/test_linux/test_generic/__init__.py -------------------------------------------------------------------------------- /tests/test_linux/test_generic/test_basic.py: -------------------------------------------------------------------------------- 1 | import os 2 | from contextlib import ExitStack 3 | 4 | import pytest 5 | 6 | from pyroute2 import GenericNetlinkSocket, TaskStats 7 | from pyroute2.netlink import nlmsg 8 | 9 | 10 | def test_bind_first(): 11 | with ExitStack() as sockets: 12 | ts = sockets.enter_context(TaskStats()) 13 | gs = sockets.enter_context(GenericNetlinkSocket()) 14 | 15 | with pytest.raises(RuntimeError) as ets: 16 | ts.get_pid_stat(os.getpid()) 17 | 18 | with pytest.raises(RuntimeError) as egs: 19 | gs.nlm_request(nlmsg(), gs.prid) 20 | 21 | assert ets.value.args == egs.value.args 22 | -------------------------------------------------------------------------------- /tests/test_linux/test_generic/test_mptcp.py: -------------------------------------------------------------------------------- 1 | from pr2test.context_manager import skip_if_not_supported 2 | from pr2test.marks import require_root 3 | 4 | from pyroute2 import MPTCP 5 | 6 | pytestmark = [require_root()] 7 | 8 | 9 | def get_endpoints(mptcp): 10 | return dict( 11 | ( 12 | x.get_nested('MPTCP_PM_ATTR_ADDR', 'MPTCP_PM_ADDR_ATTR_ADDR4'), 13 | x.get_nested('MPTCP_PM_ATTR_ADDR', 'MPTCP_PM_ADDR_ATTR_ID'), 14 | ) 15 | for x in mptcp.endpoint('show') 16 | ) 17 | 18 | 19 | def get_limits(mptcp): 20 | return [ 21 | ( 22 | x.get_attr('MPTCP_PM_ATTR_SUBFLOWS'), 23 | x.get_attr('MPTCP_PM_ATTR_RCV_ADD_ADDRS'), 24 | ) 25 | for x in mptcp.limits('show') 26 | ][0] 27 | 28 | 29 | @skip_if_not_supported 30 | def test_enpoint_add_addr4(context): 31 | with MPTCP() as mptcp: 32 | ipaddrs = [context.new_ipaddr for _ in range(3)] 33 | for ipaddr in ipaddrs: 34 | mptcp.endpoint('add', addr=ipaddr) 35 | mapping = get_endpoints(mptcp) 36 | assert set(mapping) >= set(ipaddrs) 37 | for ipaddr in ipaddrs: 38 | mptcp.endpoint('del', addr=ipaddr, id=mapping[ipaddr]) 39 | assert not set(get_endpoints(mptcp)).intersection(set(ipaddrs)) 40 | 41 | 42 | @skip_if_not_supported 43 | def test_limits(context): 44 | with MPTCP() as mptcp: 45 | save_subflows, save_rcv_add = get_limits(mptcp) 46 | mptcp.limits('set', subflows=2, rcv_add_addrs=3) 47 | assert get_limits(mptcp) == (2, 3) 48 | mptcp.limits('set', subflows=save_subflows, rcv_add_addrs=save_rcv_add) 49 | assert get_limits(mptcp) == (save_subflows, save_rcv_add) 50 | -------------------------------------------------------------------------------- /tests/test_linux/test_generic/test_taskstats.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from pr2test.marks import require_root 4 | 5 | from pyroute2 import TaskStats 6 | 7 | pytestmark = [require_root()] 8 | 9 | 10 | def test_basic(): 11 | with TaskStats() as ts: 12 | ts.bind() 13 | ret = ts.get_pid_stat(os.getpid())[0] 14 | 15 | pid = ret.get_nested('TASKSTATS_TYPE_AGGR_PID', 'TASKSTATS_TYPE_PID') 16 | stats = ret.get_nested( 17 | 'TASKSTATS_TYPE_AGGR_PID', 'TASKSTATS_TYPE_STATS' 18 | ) 19 | 20 | assert stats['cpu_count'] > 0 21 | assert stats['ac_pid'] == pid == os.getpid() 22 | assert stats['coremem'] > 0 23 | assert stats['virtmem'] > 0 24 | -------------------------------------------------------------------------------- /tests/test_linux/test_integration/test_serialize.py: -------------------------------------------------------------------------------- 1 | import json 2 | import pickle 3 | 4 | 5 | def _check(context, loaded): 6 | names = set([x.get_attr('IFLA_IFNAME') for x in loaded]) 7 | indices = set([x['index'] for x in loaded]) 8 | assert names == {x.ifname for x in context.ndb.interfaces.dump()} 9 | assert indices == {x.index for x in context.ndb.interfaces.dump()} 10 | 11 | 12 | def test_pickle(context): 13 | links = tuple(context.ipr.link('dump')) 14 | saved = pickle.dumps(links) 15 | loaded = pickle.loads(saved) 16 | _check(context, loaded) 17 | 18 | 19 | def test_json(context): 20 | links = tuple(context.ipr.link('dump')) 21 | saved = json.dumps([x.dump() for x in links]) 22 | msg_type = type(links[0]) 23 | loaded = [msg_type().load(x) for x in json.loads(saved)] 24 | _check(context, loaded) 25 | 26 | 27 | def test_dump(context): 28 | links = tuple(context.ipr.link('dump')) 29 | saved = [(type(x), x.dump()) for x in links] 30 | loaded = [x[0]().load(x[1]) for x in saved] 31 | _check(context, loaded) 32 | -------------------------------------------------------------------------------- /tests/test_linux/test_ipr/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/tests/test_linux/test_ipr/__init__.py -------------------------------------------------------------------------------- /tests/test_linux/test_ipr/test_basic.py: -------------------------------------------------------------------------------- 1 | import socket 2 | 3 | import pytest 4 | 5 | from pyroute2 import IPRoute 6 | from pyroute2.netlink import nlmsg 7 | 8 | 9 | def test_context_manager(): 10 | with IPRoute() as ipr: 11 | ipr.get_links() 12 | 13 | 14 | def test_multiple_instances(): 15 | ipr1 = IPRoute() 16 | ipr2 = IPRoute() 17 | ipr1.close() 18 | ipr2.close() 19 | 20 | 21 | def test_close(): 22 | ipr = IPRoute() 23 | ipr.get_links() 24 | ipr.close() 25 | # Shouldn't be able to use the socket after closing 26 | with pytest.raises(socket.error): 27 | ipr.link('get', index=1) 28 | 29 | 30 | def test_fileno(): 31 | with pytest.raises(OSError) as e: 32 | IPRoute(fileno=2048) 33 | assert e.value.errno == 9 # sendto -> Bad file descriptor 34 | 35 | 36 | def test_get_policy_map(context): 37 | assert isinstance(context.ipr.get_policy_map(), dict) 38 | 39 | 40 | def test_register_policy(context): 41 | context.ipr.register_policy(100, nlmsg) 42 | context.ipr.register_policy({101: nlmsg}) 43 | context.ipr.register_policy(102, nlmsg) 44 | 45 | assert context.ipr.get_policy_map()[100] == nlmsg 46 | assert context.ipr.get_policy_map(101)[101] == nlmsg 47 | assert context.ipr.get_policy_map([102])[102] == nlmsg 48 | 49 | context.ipr.unregister_policy(100) 50 | context.ipr.unregister_policy([101]) 51 | context.ipr.unregister_policy({102: nlmsg}) 52 | 53 | assert 100 not in context.ipr.get_policy_map() 54 | assert 101 not in context.ipr.get_policy_map() 55 | assert 102 not in context.ipr.get_policy_map() 56 | -------------------------------------------------------------------------------- /tests/test_linux/test_ipr/test_callbacks.py: -------------------------------------------------------------------------------- 1 | from pr2test.marks import require_root 2 | 3 | pytestmark = [require_root()] 4 | 5 | 6 | def callback(msg, cb_context): 7 | cb_context['counter'] += 1 8 | 9 | 10 | def test_callbacks_positive(context): 11 | ifname = context.new_ifname 12 | cb_context = {'counter': 0} 13 | interface = context.ndb.interfaces.create( 14 | ifname=ifname, kind='dummy' 15 | ).commit() 16 | 17 | context.ipr.register_callback( 18 | callback, 19 | lambda x: x.get('index', None) == interface['index'], 20 | (cb_context,), 21 | ) 22 | context.ipr.link('set', index=interface['index'], state='up') 23 | context.ipr.link('get', index=interface['index']) 24 | counter = cb_context['counter'] 25 | assert counter > 0 26 | context.ipr.unregister_callback(callback) 27 | context.ipr.link('set', index=interface['index'], state='down') 28 | context.ipr.link('get', index=interface['index']) 29 | assert cb_context['counter'] == counter 30 | 31 | 32 | def test_callbacks_negative(context): 33 | ifname = context.new_ifname 34 | cb_context = {'counter': 0} 35 | interface = context.ndb.interfaces.create( 36 | ifname=ifname, kind='dummy' 37 | ).commit() 38 | 39 | context.ipr.register_callback( 40 | callback, lambda x: x.get('index', None) == -1, (cb_context,) 41 | ) 42 | context.ipr.link('set', index=interface['index'], state='up') 43 | context.ipr.link('get', index=interface['index']) 44 | counter = cb_context['counter'] 45 | assert counter == 0 46 | -------------------------------------------------------------------------------- /tests/test_linux/test_ipr/test_config.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pr2test.marks import require_root 3 | 4 | from pyroute2 import IPRoute 5 | 6 | pytestmark = [require_root()] 7 | 8 | 9 | @pytest.mark.parametrize('nlm_echo', (True, False)) 10 | def test_echo_route(context, nlm_echo): 11 | index, ifname = context.default_interface 12 | address = context.new_ipaddr 13 | gateway = context.get_ipaddr(r=0) 14 | target = context.get_ipaddr(r=1) 15 | spec = {'dst': target, 'dst_len': 32, 'gateway': gateway, 'oif': index} 16 | nla_check = {} 17 | for key, value in spec.items(): 18 | nla_check[key] = value if nlm_echo else None 19 | with IPRoute(nlm_echo=nlm_echo) as ipr: 20 | context.ipr.addr('add', index=index, address=address, prefixlen=24) 21 | context.ipr.poll(context.ipr.addr, 'dump', address=address) 22 | response = tuple(ipr.route('add', **spec))[0] 23 | for key, value in nla_check.items(): 24 | assert response.get(key) == value 25 | -------------------------------------------------------------------------------- /tests/test_linux/test_ipr/test_ipbatch.py: -------------------------------------------------------------------------------- 1 | from pr2test.marks import require_root 2 | 3 | from pyroute2 import IPBatch 4 | 5 | pytestmark = [require_root()] 6 | 7 | 8 | def test_link_add(context): 9 | ifname = context.new_ifname 10 | 11 | ipb = IPBatch() 12 | ipb.link('add', ifname=ifname, kind='dummy') 13 | data = ipb.batch 14 | ipb.reset() 15 | ipb.close() 16 | context.ipr.sendto(data, (0, 0)) 17 | context.ndb.interfaces.wait(ifname=ifname, timeout=3) 18 | -------------------------------------------------------------------------------- /tests/test_linux/test_ipr/test_link_create.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pr2test.marks import require_root 3 | 4 | from pyroute2.netlink.rtnl.ifinfmsg import ifinfmsg 5 | 6 | pytestmark = [require_root()] 7 | 8 | 9 | @pytest.mark.parametrize('smode', ('IPVLAN_MODE_L2', 'IPVLAN_MODE_L3')) 10 | def test_create_ipvlan(context, smode): 11 | master = context.new_ifname 12 | ipvlan = context.new_ifname 13 | # create the master link 14 | index = context.ndb.interfaces.create( 15 | ifname=master, kind='dummy' 16 | ).commit()['index'] 17 | # check modes 18 | # maybe move modes dict somewhere else? 19 | cmode = ifinfmsg.ifinfo.data_map['ipvlan'].modes[smode] 20 | assert ifinfmsg.ifinfo.data_map['ipvlan'].modes[cmode] == smode 21 | # create ipvlan 22 | context.ipr.link( 23 | 'add', ifname=ipvlan, kind='ipvlan', link=index, mode=cmode 24 | ) 25 | interface = context.ndb.interfaces.wait(ifname=ipvlan, timeout=5) 26 | assert interface['link'] == index 27 | assert interface['ipvlan_mode'] == cmode 28 | -------------------------------------------------------------------------------- /tests/test_linux/test_ipr/test_match.py: -------------------------------------------------------------------------------- 1 | from functools import partial 2 | 3 | 4 | def test_match_callable(context): 5 | assert len(tuple(context.ipr.get_links(match=partial(lambda x: x)))) > 0 6 | -------------------------------------------------------------------------------- /tests/test_linux/test_ipr/test_ntables.py: -------------------------------------------------------------------------------- 1 | def _test_ntables(self): 2 | setA = set( 3 | filter( 4 | lambda x: x is not None, 5 | [ 6 | x.get_attr('NDTA_PARMS').get_attr('NDTPA_IFINDEX') 7 | for x in self.ip.get_ntables() 8 | ], 9 | ) 10 | ) 11 | setB = set([x['index'] for x in self.ip.get_links()]) 12 | assert setA == setB 13 | -------------------------------------------------------------------------------- /tests/test_linux/test_ipr/test_rule.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import struct 3 | 4 | import pytest 5 | from pr2test.marks import require_root 6 | 7 | pytestmark = [require_root()] 8 | 9 | 10 | def test_flush_rules(context): 11 | ifaddr1 = context.new_ipaddr 12 | ifaddr2 = context.new_ipaddr 13 | init = len(tuple(context.ipr.get_rules(family=socket.AF_INET))) 14 | assert ( 15 | len(tuple(context.ipr.get_rules(priority=lambda x: 100 < x < 500))) 16 | == 0 17 | ) 18 | context.ipr.rule('add', table=10, priority=110) 19 | context.ipr.rule('add', table=15, priority=150, action='FR_ACT_PROHIBIT') 20 | context.ipr.rule('add', table=20, priority=200, src=ifaddr1) 21 | context.ipr.rule('add', table=25, priority=250, dst=ifaddr2) 22 | assert ( 23 | len(tuple(context.ipr.get_rules(priority=lambda x: 100 < x < 500))) 24 | == 4 25 | ) 26 | assert len(tuple(context.ipr.get_rules(src=ifaddr1))) == 1 27 | assert len(tuple(context.ipr.get_rules(dst=ifaddr2))) == 1 28 | context.ipr.flush_rules( 29 | family=socket.AF_INET, priority=lambda x: 100 < x < 500 30 | ) 31 | assert ( 32 | len(tuple(context.ipr.get_rules(priority=lambda x: 100 < x < 500))) 33 | == 0 34 | ) 35 | assert len(tuple(context.ipr.get_rules(src=ifaddr1))) == 0 36 | assert len(tuple(context.ipr.get_rules(dst=ifaddr2))) == 0 37 | assert len(tuple(context.ipr.get_rules(family=socket.AF_INET))) == init 38 | 39 | 40 | def test_bad_table(context): 41 | with pytest.raises(struct.error): 42 | context.ipr.rule('add', table=-1, priority=32000) 43 | -------------------------------------------------------------------------------- /tests/test_linux/test_ipr/test_stress.py: -------------------------------------------------------------------------------- 1 | import os 2 | import socket 3 | 4 | from pr2test.marks import require_root 5 | 6 | from pyroute2 import NetlinkDumpInterrupted 7 | 8 | pytestmark = [require_root()] 9 | 10 | 11 | def test_mass_ipv6(context): 12 | # 13 | ipv6net = context.new_ip6net 14 | base = str(ipv6net.network) + '{0}' 15 | limit = int(os.environ.get('PYROUTE2_SLIMIT', '0x800'), 16) 16 | index, ifname = context.default_interface 17 | 18 | # add addresses 19 | for idx in range(limit): 20 | context.ipr.addr( 21 | 'add', 22 | index=index, 23 | family=socket.AF_INET6, 24 | address=base.format(hex(idx)[2:]), 25 | prefixlen=48, 26 | ) 27 | 28 | # assert addresses in two steps, to ease debug 29 | addrs = [] 30 | for _ in range(3): 31 | try: 32 | addrs = tuple(context.ipr.get_addr(family=socket.AF_INET6)) 33 | break 34 | except NetlinkDumpInterrupted: 35 | pass 36 | else: 37 | raise Exception('could not dump addresses') 38 | assert len(addrs) >= limit 39 | -------------------------------------------------------------------------------- /tests/test_linux/test_ipr/test_vlan_filter.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pr2test.marks import require_root 3 | 4 | pytestmark = [require_root()] 5 | 6 | 7 | def test_vlan_filter_dump(context): 8 | ifname1 = context.new_ifname 9 | ifname2 = context.new_ifname 10 | context.ndb.interfaces.create( 11 | ifname=ifname1, kind='bridge', state='up' 12 | ).commit() 13 | context.ndb.interfaces.create( 14 | ifname=ifname2, kind='bridge', state='up' 15 | ).commit() 16 | assert len(tuple(context.ipr.get_vlans())) >= 2 17 | for name in (ifname1, ifname2): 18 | assert len(tuple(context.ipr.get_vlans(ifname=name))) == 1 19 | assert ( 20 | tuple(context.ipr.get_vlans(ifname=name))[0].get_attr( 21 | 'IFLA_IFNAME' 22 | ) 23 | ) == name 24 | assert ( 25 | tuple(context.ipr.get_vlans(ifname=name))[0].get_nested( 26 | 'IFLA_AF_SPEC', 'IFLA_BRIDGE_VLAN_INFO' 27 | ) 28 | )['vid'] == 1 29 | 30 | 31 | @pytest.mark.parametrize( 32 | 'arg_name,vid_spec,vid', 33 | ( 34 | ('vlan_info', {'vid': 568}, 568), 35 | ('af_spec', {'attrs': [['IFLA_BRIDGE_VLAN_INFO', {'vid': 567}]]}, 567), 36 | ), 37 | ) 38 | def _test_vlan_filter_add(context, arg_name, vid_spec, vid): 39 | ifname_port = context.new_ifname 40 | ifname_bridge = context.new_ifname 41 | port = context.ndb.interfaces.create( 42 | ifname=ifname_port, kind='dummy', state='up' 43 | ).commit() 44 | ( 45 | context.ndb.interfaces.create( 46 | ifname=ifname_bridge, kind='bridge', state='up' 47 | ) 48 | .add_port(ifname_port) 49 | .commit() 50 | ) 51 | assert vid not in context.ndb.vlans 52 | spec = {'index': port['index'], arg_name: vid_spec} 53 | context.ipr.vlan_filter('add', **spec) 54 | assert context.ndb.vlans.wait(vid=vid, timeout=5) 55 | context.ipr.vlan_filter('del', **spec) 56 | assert context.ndb.vlans.wait(vid=vid, timeout=5, action='remove') 57 | -------------------------------------------------------------------------------- /tests/test_linux/test_ipvs.py: -------------------------------------------------------------------------------- 1 | from socket import IPPROTO_TCP 2 | 3 | import pytest 4 | 5 | from pyroute2 import IPVS, IPVSService 6 | 7 | 8 | class Context: 9 | def __init__(self, request, tmpdir): 10 | self.ipvs = IPVS() 11 | self.services = [] 12 | 13 | def new_service(self, addr, port, protocol): 14 | service = IPVSService(addr=addr, port=port, protocol=protocol) 15 | self.ipvs.service("add", service=service) 16 | self.services.append(service) 17 | return service 18 | 19 | def teardown(self): 20 | for service in self.services: 21 | self.ipvs.service("del", service=service) 22 | self.services = [] 23 | 24 | def service(self, command, service=None): 25 | return self.ipvs.service(command, service) 26 | 27 | def dest(self, command, service, dest=None): 28 | return self.ipvs.dest(command, service, dest) 29 | 30 | 31 | @pytest.fixture 32 | def ipvsadm(request, tmpdir): 33 | ctx = Context(request, tmpdir) 34 | yield ctx 35 | ctx.teardown() 36 | 37 | 38 | def test_basic(ipvsadm, context): 39 | ipaddr = context.new_ipaddr 40 | ( 41 | context.ndb.interfaces[context.default_interface.ifname] 42 | .add_ip(f"{ipaddr}/24") 43 | .commit() 44 | ) 45 | ipvsadm.new_service(addr=ipaddr, port=6000, protocol=IPPROTO_TCP) 46 | buffer = [] 47 | for service in ipvsadm.service("dump"): 48 | if ( 49 | service.get(('service', 'addr')) == ipaddr 50 | and service.get(('service', 'port')) == 6000 51 | and service.get(('service', 'protocol')) == IPPROTO_TCP 52 | ): 53 | break 54 | buffer.append(service) 55 | else: 56 | raise KeyError('service not found') 57 | print(buffer) 58 | -------------------------------------------------------------------------------- /tests/test_linux/test_iwutil.py: -------------------------------------------------------------------------------- 1 | import collections 2 | import errno 3 | 4 | import pytest 5 | from pr2test.marks import require_root 6 | 7 | from pyroute2 import IW, IPRoute 8 | from pyroute2.netlink.exceptions import NetlinkError 9 | 10 | 11 | @pytest.fixture 12 | def ctx(): 13 | iw = None 14 | ifname = None 15 | wiphy = None 16 | index = None 17 | try: 18 | iw = IW() 19 | except NetlinkError as e: 20 | if e.code == errno.ENOENT: 21 | pytest.skip('nl80211 not supported') 22 | raise 23 | ifaces = iw.get_interfaces_dump() 24 | if not ifaces: 25 | raise pytest.skip('no wireless interfaces found') 26 | for i in ifaces: 27 | ifname = i.get_attr('NL80211_ATTR_IFNAME') 28 | index = i.get_attr('NL80211_ATTR_IFINDEX') 29 | wiphy = i.get_attr('NL80211_ATTR_WIPHY') 30 | if index: 31 | break 32 | else: 33 | pytest.skip('can not detect the interface to use') 34 | 35 | yield collections.namedtuple( 36 | 'WirelessContext', ['iw', 'ifname', 'index', 'wiphy'] 37 | )(iw, ifname, index, wiphy) 38 | 39 | iw.close() 40 | 41 | 42 | def test_list_wiphy(ctx): 43 | ctx.iw.list_wiphy() 44 | 45 | 46 | def test_list_dev(ctx): 47 | ctx.iw.list_dev() 48 | 49 | 50 | @require_root 51 | def test_scan(ctx): 52 | with IPRoute() as ipr: 53 | ipr.link('set', index=ctx.index, state='up') 54 | ctx.iw.scan(ctx.index) 55 | -------------------------------------------------------------------------------- /tests/test_linux/test_ndb/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/tests/test_linux/test_ndb/__init__.py -------------------------------------------------------------------------------- /tests/test_linux/test_ndb/test_altnames.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pr2test.context_manager import make_test_matrix, skip_if_not_supported 3 | from pr2test.marks import require_root 4 | from pr2test.tools import interface_exists 5 | 6 | pytestmark = [require_root()] 7 | 8 | test_matrix = make_test_matrix( 9 | targets=['local', 'netns'], dbs=['sqlite3/:memory:', 'postgres/pr2test'] 10 | ) 11 | 12 | 13 | @pytest.mark.xfail(reason='flaky test, to be fixed') 14 | @pytest.mark.parametrize('context', test_matrix, indirect=True) 15 | @skip_if_not_supported 16 | def test_altname_complex(context): 17 | index, ifname = context.default_interface 18 | altname1 = context.new_ifname 19 | altname2 = context.new_ifname 20 | with context.ndb.interfaces[ifname] as i: 21 | i.add_altname(altname1) 22 | 23 | assert interface_exists(context.netns, altname=altname1) 24 | assert not interface_exists(context.netns, altname=altname2) 25 | 26 | with context.ndb.interfaces[ifname] as i: 27 | i.del_altname(altname1) 28 | i.add_altname(altname2) 29 | 30 | assert interface_exists(context.netns, altname=altname2) 31 | assert not interface_exists(context.netns, altname=altname1) 32 | 33 | with context.ndb.interfaces[ifname] as i: 34 | i.del_altname(altname2) 35 | 36 | assert not interface_exists(context.netns, altname=altname1) 37 | assert not interface_exists(context.netns, altname=altname2) 38 | -------------------------------------------------------------------------------- /tests/test_linux/test_ndb/test_backup.py: -------------------------------------------------------------------------------- 1 | import sqlite3 2 | import uuid 3 | 4 | 5 | def test_file_backup(context): 6 | filename = str(uuid.uuid4()) + '-backup.db' 7 | context.ndb.backup(filename) 8 | backup = sqlite3.connect(filename) 9 | cursor = backup.cursor() 10 | cursor.execute('SELECT f_IFLA_IFNAME FROM interfaces WHERE f_index > 0') 11 | interfaces_from_backup = {x[0] for x in cursor.fetchall()} 12 | with context.ndb.interfaces.summary() as summary: 13 | interfaces_from_ndb = {x.ifname for x in summary} 14 | assert interfaces_from_ndb == interfaces_from_backup 15 | -------------------------------------------------------------------------------- /tests/test_linux/test_ndb/test_chaotic.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pr2test.marks import require_root 3 | from pr2test.tools import address_exists 4 | 5 | from pyroute2 import NDB 6 | 7 | pytestmark = [require_root()] 8 | 9 | 10 | @pytest.mark.xfail(reason='flaky test, only to collect failure logs') 11 | def __test_add_del_ip_dict(context): 12 | ifname = context.new_ifname 13 | ifaddr1 = context.new_ipaddr 14 | ifaddr2 = context.new_ipaddr 15 | log_spec = ( 16 | context.spec.log_spec[0] + '.chaotic', 17 | context.spec.log_spec[1], 18 | ) 19 | 20 | with NDB( 21 | log=log_spec, 22 | sources=[ 23 | { 24 | 'target': 'localhost', 25 | 'kind': 'ChaoticIPRoute', 26 | 'success_rate': 0.98, 27 | } 28 | ], 29 | ) as test_ndb: 30 | ( 31 | test_ndb.interfaces.create( 32 | ifname=ifname, kind='dummy', state='down' 33 | ) 34 | .add_ip({'address': ifaddr1, 'prefixlen': 24}) 35 | .add_ip({'address': ifaddr2, 'prefixlen': 24}) 36 | .commit() 37 | ) 38 | 39 | assert address_exists(context.netns, ifname=ifname, address=ifaddr1) 40 | assert address_exists(context.netns, ifname=ifname, address=ifaddr2) 41 | 42 | ( 43 | test_ndb.interfaces[{'ifname': ifname}] 44 | .del_ip({'address': ifaddr2, 'prefixlen': 24}) 45 | .del_ip({'address': ifaddr1, 'prefixlen': 24}) 46 | .commit() 47 | ) 48 | 49 | assert not address_exists( 50 | context.netns, ifname=ifname, address=ifaddr1 51 | ) 52 | assert not address_exists( 53 | context.netns, ifname=ifname, address=ifaddr2 54 | ) 55 | -------------------------------------------------------------------------------- /tests/test_linux/test_ndb/test_db.py: -------------------------------------------------------------------------------- 1 | import sqlite3 2 | 3 | import pytest 4 | 5 | from pyroute2 import NDB 6 | 7 | try: 8 | import psycopg2 9 | except ImportError: 10 | pytest.skip('no psycopg2 module installed', allow_module_level=True) 11 | 12 | 13 | def test_no_cleanup(spec): 14 | # start and stop the DB, leaving all the data in the DB file 15 | NDB( 16 | db_provider='sqlite3', 17 | db_spec=spec.db_spec, 18 | db_cleanup=False, 19 | log=spec.log_spec, 20 | ).close() 21 | 22 | # open the DB file 23 | db = sqlite3.connect(spec.db_spec) 24 | cursor = db.cursor() 25 | cursor.execute('SELECT * FROM interfaces') 26 | interfaces = cursor.fetchall() 27 | 28 | # at least two records: idx 0 and loopback 29 | assert len(interfaces) > 1 30 | # all the interfaces must be of the same source, 'localhost' 31 | assert set([x[0] for x in interfaces]) == set(('localhost',)) 32 | 33 | 34 | def test_postgres_fail(spec): 35 | try: 36 | NDB( 37 | db_provider='postgres', 38 | db_spec={'dbname': 'some-nonsense-db-name'}, 39 | log=spec.log_spec, 40 | ).close() 41 | except psycopg2.OperationalError: 42 | return 43 | 44 | raise Exception('postgresql exception was expected') 45 | -------------------------------------------------------------------------------- /tests/test_linux/test_ndb/test_examples.py: -------------------------------------------------------------------------------- 1 | import os 2 | import pathlib 3 | import sys 4 | 5 | import pytest 6 | from pr2test.marks import require_root 7 | 8 | pytestmark = [require_root()] 9 | 10 | 11 | def get_examples(*argv): 12 | root = pathlib.Path(os.environ['WORKSPACE']) 13 | examples = [ 14 | file 15 | for file in root.joinpath(*argv).iterdir() 16 | if not file.name.endswith('.swp') 17 | ] 18 | return { 19 | 'argnames': 'example', 20 | 'argvalues': examples, 21 | 'ids': [x.name for x in examples], 22 | } 23 | 24 | 25 | @pytest.mark.parametrize(**get_examples('examples', 'pyroute2-cli')) 26 | def test_cli_examples(example, pytester, context): 27 | with example.open('r') as text: 28 | result = pytester.run('pyroute2-cli', stdin=text) 29 | assert result.ret == 0 30 | 31 | 32 | @pytest.mark.parametrize(**get_examples('examples', 'ndb')) 33 | def test_ndb_examples(example, pytester, context): 34 | argv = [] 35 | with example.open('r') as text: 36 | for line in text.readlines(): 37 | line = line.strip() 38 | if line == ':notest:': 39 | pytest.skip() 40 | elif line.startswith(':test:argv:'): 41 | argv.append(line.split(':')[-1]) 42 | elif line.startswith(':test:environ:'): 43 | key, value = line.split(':')[-1].split('=') 44 | os.environ[key] = value 45 | result = pytester.run(sys.executable, example.as_posix(), *argv) 46 | assert result.ret == 0 47 | 48 | 49 | def test_basic(tmpdir, pytester, context): 50 | pytester.makefile('.pr2', test='interfaces lo mtu') 51 | with open('test.pr2', 'r') as text: 52 | result = pytester.run("pyroute2-cli", stdin=text) 53 | assert result.ret == 0 54 | assert result.outlines == ['65536'] 55 | -------------------------------------------------------------------------------- /tests/test_linux/test_ndb/test_fdb.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pr2test.context_manager import make_test_matrix 3 | from pr2test.marks import require_root 4 | from pr2test.tools import fdb_record_exists 5 | 6 | pytestmark = [require_root()] 7 | 8 | test_matrix = make_test_matrix( 9 | targets=['local', 'netns'], 10 | tables=[None], 11 | dbs=['sqlite3/:memory:', 'postgres/pr2test'], 12 | ) 13 | 14 | 15 | @pytest.mark.parametrize('context', test_matrix, indirect=True) 16 | def test_fdb_create(context): 17 | spec = { 18 | 'ifindex': context.default_interface.index, 19 | 'lladdr': '00:11:22:33:44:55', 20 | } 21 | 22 | context.ndb.fdb.create(**spec).commit() 23 | assert fdb_record_exists(context.netns, **spec) 24 | 25 | context.ndb.fdb[spec].remove().commit() 26 | assert not fdb_record_exists(context.netns, **spec) 27 | -------------------------------------------------------------------------------- /tests/test_linux/test_ndb/test_init.py: -------------------------------------------------------------------------------- 1 | import uuid 2 | from socket import AF_INET, AF_INET6 3 | 4 | import pytest 5 | from pr2test.marks import require_root 6 | 7 | from pyroute2 import NDB 8 | from pyroute2.netlink.rtnl import RTMGRP_IPV4_IFADDR, RTMGRP_LINK 9 | 10 | pytestmark = [require_root()] 11 | 12 | 13 | @pytest.mark.parametrize('kind', ('local', 'netns')) 14 | def test_netlink_groups(kind): 15 | spec = { 16 | 'target': 'localhost', 17 | 'kind': kind, 18 | 'groups': RTMGRP_LINK | RTMGRP_IPV4_IFADDR, 19 | } 20 | if kind == 'netns': 21 | spec['netns'] = str(uuid.uuid4()) 22 | with NDB(sources=[spec]) as ndb: 23 | assert 'lo' in ndb.interfaces 24 | with ndb.interfaces['lo'] as lo: 25 | lo.set(state='up') 26 | addresses4 = ndb.addresses.dump() 27 | addresses4.select_records(family=AF_INET) 28 | assert addresses4.count() > 0 29 | addresses6 = ndb.addresses.dump() 30 | addresses6.select_records(family=AF_INET6) 31 | assert addresses6.count() == 0 32 | routes = ndb.routes.dump() 33 | assert routes.count() == 0 34 | neighbours = ndb.neighbours.dump() 35 | assert neighbours.count() == 0 36 | -------------------------------------------------------------------------------- /tests/test_linux/test_ndb/test_probe.py: -------------------------------------------------------------------------------- 1 | import errno 2 | 3 | import pytest 4 | from pr2test.context_manager import make_test_matrix, skip_if_not_supported 5 | from pr2test.marks import require_root 6 | 7 | from pyroute2 import NetlinkError 8 | 9 | pytestmark = [require_root()] 10 | test_matrix = make_test_matrix(targets=['local', 'netns']) 11 | 12 | 13 | @pytest.mark.parametrize('context', test_matrix, indirect=True) 14 | @skip_if_not_supported 15 | def test_ping_ok(context): 16 | index, ifname = context.default_interface 17 | ipaddr = context.new_ipaddr 18 | 19 | with context.ndb.interfaces[ifname] as i: 20 | i.add_ip(address=ipaddr, prefixlen=24) 21 | i.set(state='up') 22 | 23 | with context.ndb.interfaces['lo'] as i: 24 | i.set(state='up') 25 | 26 | context.ndb.probes.create(kind='ping', dst=ipaddr).commit() 27 | 28 | 29 | @pytest.mark.parametrize( 30 | 'context', make_test_matrix(targets=['netns']), indirect=True 31 | ) 32 | @skip_if_not_supported 33 | def test_ping_fail_ehostunreach(context): 34 | with context.ndb.interfaces['lo'] as i: 35 | i.set(state='down') 36 | with pytest.raises(NetlinkError) as e: 37 | context.ndb.probes.create(kind='ping', dst='127.0.0.1').commit() 38 | assert e.value.code == errno.EHOSTUNREACH 39 | 40 | 41 | @pytest.mark.parametrize( 42 | 'context', make_test_matrix(targets=['netns']), indirect=True 43 | ) 44 | @skip_if_not_supported 45 | def test_ping_fail_etimedout(context): 46 | index, ifname = context.default_interface 47 | ipaddr = context.new_ipaddr 48 | target = context.new_ipaddr 49 | 50 | with context.ndb.interfaces[ifname] as i: 51 | i.add_ip(address=ipaddr, prefixlen=24) 52 | i.set(state='up') 53 | with context.ndb.interfaces['lo'] as i: 54 | i.set(state='up') 55 | with pytest.raises(NetlinkError) as e: 56 | context.ndb.probes.create(kind='ping', dst=target).commit() 57 | assert e.value.code == errno.ETIMEDOUT 58 | -------------------------------------------------------------------------------- /tests/test_linux/test_ndb/test_rules.py: -------------------------------------------------------------------------------- 1 | from socket import AF_INET6 2 | 3 | import pytest 4 | from pr2test.context_manager import make_test_matrix 5 | from pr2test.marks import require_root 6 | from pr2test.tools import rule_exists 7 | 8 | pytestmark = [require_root()] 9 | 10 | test_matrix = make_test_matrix( 11 | targets=['local', 'netns'], 12 | tables=[100, 10000], 13 | dbs=['sqlite3/:memory:', 'postgres/pr2test'], 14 | ) 15 | 16 | 17 | @pytest.mark.parametrize('context', test_matrix, indirect=True) 18 | def test_explicit_ipv6_src(context): 19 | ipnet = context.new_ip6net 20 | table = context.table 21 | 22 | spec = { 23 | 'family': AF_INET6, 24 | 'src': ipnet.network, 25 | 'src_len': ipnet.netmask, 26 | 'table': table, 27 | 'priority': 50, 28 | } 29 | context.register_rule(spec) 30 | 31 | context.ndb.rules.create(**spec).commit() 32 | assert rule_exists(context.netns, **spec) 33 | 34 | context.ndb.rules[spec].remove().commit() 35 | assert not rule_exists(context.netns, **spec) 36 | 37 | 38 | @pytest.mark.parametrize('context', test_matrix, indirect=True) 39 | def test_implicit_ipv6_src(context): 40 | ipnet = context.new_ip6net 41 | table = context.table 42 | 43 | spec = { 44 | 'src': ipnet.network, 45 | 'src_len': ipnet.netmask, 46 | 'table': table, 47 | 'priority': 50, 48 | } 49 | search_spec = spec.copy() 50 | search_spec['family'] = AF_INET6 51 | context.register_rule(search_spec) 52 | 53 | context.ndb.rules.create(**spec).commit() 54 | assert rule_exists(context.netns, **search_spec) 55 | 56 | context.ndb.rules[spec].remove().commit() 57 | assert not rule_exists(context.netns, **search_spec) 58 | -------------------------------------------------------------------------------- /tests/test_linux/test_nlmsg/test_nlmsg.py: -------------------------------------------------------------------------------- 1 | from pr2test.marks import require_root 2 | 3 | pytestmark = [require_root()] 4 | 5 | 6 | def test_nlmsg_operators(context): 7 | ifname = context.new_ifname 8 | ipaddr1 = context.new_ipaddr 9 | ipaddr2 = context.new_ipaddr 10 | interface = ( 11 | context.ndb.interfaces.create(ifname=ifname, kind='dummy', state='up') 12 | .add_ip(f'{ipaddr1}/24') 13 | .add_ip(f'{ipaddr2}/24') 14 | .commit() 15 | ) 16 | 17 | r = tuple(context.ipr.addr('dump', index=interface['index'])) 18 | complement = r[0] - r[1] 19 | intersection = r[0] & r[1] 20 | 21 | assert complement.get_attr('IFA_ADDRESS') == ipaddr1 22 | assert complement.get_attr('IFA_LABEL') is None 23 | assert 'prefixlen' not in complement 24 | assert 'index' not in complement 25 | 26 | assert intersection.get_attr('IFA_ADDRESS') is None 27 | assert intersection.get_attr('IFA_LABEL') == ifname 28 | assert intersection['prefixlen'] == 24 29 | assert intersection['index'] == context.ndb.interfaces[ifname]['index'] 30 | 31 | 32 | def test_nlmsg_compare_equal(context): 33 | lvalue = tuple(context.ipr.get_links())[0] 34 | rvalue = tuple(context.ipr.get_links())[0] 35 | assert lvalue is not rvalue 36 | assert lvalue == rvalue 37 | 38 | 39 | def test_nlmsg_compare_not_equal(context): 40 | lvalue = tuple(context.ipr.get_links())[0] 41 | rvalue = tuple(context.ipr.get_links())[1] 42 | assert lvalue is not rvalue 43 | assert lvalue != rvalue 44 | 45 | 46 | def test_nlmsg_compare_int(context): 47 | lvalue = tuple(context.ipr.get_links())[0] 48 | rvalue = 42 49 | assert lvalue is not rvalue 50 | assert lvalue != rvalue 51 | -------------------------------------------------------------------------------- /tests/test_linux/test_tc/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/tests/test_linux/test_tc/__init__.py -------------------------------------------------------------------------------- /tests/test_linux/test_wireguard/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svinota/pyroute2/1be9a52f5d9144321158f9202d686fcac3a26028/tests/test_linux/test_wireguard/__init__.py -------------------------------------------------------------------------------- /tests/test_minimal/test_iproute.py: -------------------------------------------------------------------------------- 1 | import getpass 2 | 3 | import pytest 4 | 5 | from pyroute2 import IPRoute 6 | from pyroute2.common import uifname 7 | from pyroute2.netlink import nlmsg 8 | 9 | pytestmark = [ 10 | pytest.mark.skipif(getpass.getuser() != 'root', reason='no root access') 11 | ] 12 | 13 | 14 | @pytest.fixture 15 | def ipr(): 16 | iproute = IPRoute() 17 | iproute.default_ifname = uifname() 18 | yield iproute 19 | index = iproute.link_lookup(ifname=iproute.default_ifname) 20 | if index: 21 | iproute.link('del', index=index) 22 | iproute.close() 23 | 24 | 25 | def test_dump(ipr): 26 | assert all([isinstance(message, nlmsg) for message in ipr.dump()]) 27 | 28 | 29 | def test_tuntap(ipr): 30 | ipr.link('add', ifname=ipr.default_ifname, kind='tuntap', mode='tun') 31 | ipr.poll( 32 | ipr.link, 'dump', timeout=5, ifname=ipr.default_ifname, kind='tun' 33 | ) 34 | 35 | 36 | def test_bridge(ipr): 37 | ipr.link('add', ifname=ipr.default_ifname, kind='bridge') 38 | interface = ipr.poll( 39 | ipr.link, 40 | 'dump', 41 | timeout=5, 42 | ifname=ipr.default_ifname, 43 | kind='bridge', 44 | br_stp_state=0, 45 | )[0] 46 | ipr.link('set', index=interface['index'], kind='bridge', br_stp_state=1) 47 | ipr.poll( 48 | ipr.link, 49 | 'dump', 50 | timeout=5, 51 | index=interface['index'], 52 | kind='bridge', 53 | br_stp_state=1, 54 | ) 55 | -------------------------------------------------------------------------------- /tests/test_neutron/test_ip_lib.py: -------------------------------------------------------------------------------- 1 | from inspect import signature 2 | 3 | import eventlet 4 | import pytest 5 | 6 | import pyroute2 7 | from pyroute2 import netlink, netns 8 | from pyroute2.config.eventlet import eventlet_config 9 | from pyroute2.netlink import exceptions, rtnl 10 | from pyroute2.netlink.rtnl import ifinfmsg, ndmsg 11 | 12 | eventlet.monkey_patch() 13 | eventlet_config() 14 | 15 | 16 | def parameters(func): 17 | try: 18 | return set(signature(func).parameters.keys()) 19 | except ValueError: 20 | pytest.skip('ginature check error, skip test') 21 | 22 | 23 | def test_imports(): 24 | assert parameters(pyroute2.NetNS) > set(('netns', 'flags', 'libc')) 25 | assert signature(pyroute2.IPRoute) 26 | assert issubclass(netlink.NetlinkError, Exception) 27 | assert issubclass(exceptions.NetlinkDumpInterrupted, Exception) 28 | assert netlink.NetlinkError == exceptions.NetlinkError 29 | assert netlink.nla_slot 30 | assert netlink.nla_base 31 | assert parameters(rtnl.rt_scope.get) == set(('key', 'default')) 32 | assert isinstance(rtnl.rt_proto, dict) and 'static' in rtnl.rt_proto 33 | assert parameters(netns._create) == set(('netns', 'libc', 'pid')) 34 | assert parameters(netns.listnetns) == set(('nspath',)) 35 | assert ifinfmsg.IFF_ALLMULTI == 0x200 36 | assert {state[1]: state[0] for state in ndmsg.states.items()} == { 37 | 0: 'none', 38 | 1: 'incomplete', 39 | 2: 'reachable', 40 | 4: 'stale', 41 | 8: 'delay', 42 | 16: 'probe', 43 | 32: 'failed', 44 | 64: 'noarp', 45 | 128: 'permanent', 46 | } 47 | 48 | 49 | def test_dump(): 50 | with pyroute2.IPRoute() as ipr: 51 | assert len(tuple(ipr.route('dump'))) > 0 52 | assert len(tuple(ipr.link('dump'))) > 0 53 | -------------------------------------------------------------------------------- /tests/test_openbsd/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from pyroute2 import IPRoute 4 | 5 | 6 | class BasicContextManager: 7 | def __init__(self, request, tmpdir): 8 | self.ipr = IPRoute() 9 | 10 | def teardown(self): 11 | self.ipr.close() 12 | 13 | 14 | @pytest.fixture 15 | def context(request, tmpdir): 16 | ctx = BasicContextManager(request, tmpdir) 17 | yield ctx 18 | ctx.teardown() 19 | -------------------------------------------------------------------------------- /tests/test_openbsd/test_ipr/test_basic.py: -------------------------------------------------------------------------------- 1 | from pyroute2.common import get_address_family 2 | from pyroute2.netlink.rtnl import ( 3 | RTM_NEWADDR, 4 | RTM_NEWLINK, 5 | RTM_NEWNEIGH, 6 | RTM_NEWROUTE, 7 | ) 8 | 9 | 10 | def test_get_links(context): 11 | for msg in context.ipr.get_links(): 12 | assert msg['header']['target'] == 'localhost' 13 | assert msg['header']['type'] == RTM_NEWLINK 14 | # 15 | assert msg['index'] > 0 16 | ifname = msg.get_attr('IFLA_IFNAME') 17 | assert isinstance(ifname, str) 18 | 19 | 20 | def test_get_addr(context): 21 | for msg in context.ipr.get_addr(): 22 | assert msg['header']['target'] == 'localhost' 23 | assert msg['header']['type'] == RTM_NEWADDR 24 | # 25 | addr = msg.get_attr('IFA_ADDRESS') 26 | assert isinstance(addr, str) 27 | assert msg['family'] == get_address_family(addr) 28 | assert 0 <= msg['prefixlen'] <= 128 29 | 30 | 31 | def test_get_routes(context): 32 | for msg in context.ipr.get_routes(): 33 | assert msg['header']['target'] == 'localhost' 34 | assert msg['header']['type'] == RTM_NEWROUTE 35 | 36 | 37 | def test_get_neighbours(context): 38 | for msg in context.ipr.get_neighbours(): 39 | assert msg['header']['target'] == 'localhost' 40 | assert msg['header']['type'] == RTM_NEWNEIGH 41 | # 42 | dst = msg.get_attr('NDA_DST') 43 | lladdr = msg.get_attr('NDA_LLADDR') 44 | assert msg['family'] == get_address_family(dst) 45 | assert isinstance(lladdr, str) 46 | assert len(lladdr.split(':')) == 6 47 | -------------------------------------------------------------------------------- /tests/test_process/test_catastrophe.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | from signal import SIGKILL, SIGTERM 4 | 5 | import pytest 6 | 7 | from pyroute2.process import ChildProcess 8 | 9 | 10 | def child_process_timeout(x): 11 | time.sleep(x) 12 | 13 | 14 | def child_process_die(x): 15 | os.kill(os.getpid(), x) 16 | 17 | 18 | @pytest.mark.parametrize( 19 | 'func,argv,catch,kill,exitcode', 20 | ( 21 | (child_process_timeout, [1], TimeoutError, None, -SIGKILL), 22 | (child_process_timeout, [7], TimeoutError, None, -SIGKILL), 23 | (child_process_timeout, [23], TimeoutError, None, -SIGKILL), 24 | (child_process_die, [SIGTERM], RuntimeError, None, -SIGTERM), 25 | (child_process_die, [SIGKILL], RuntimeError, None, -SIGKILL), 26 | (child_process_timeout, [30], RuntimeError, SIGTERM, -SIGTERM), 27 | (child_process_timeout, [30], RuntimeError, SIGKILL, -SIGKILL), 28 | ), 29 | ids=[ 30 | 'timeout-1', 31 | 'timeout-7', 32 | 'timeout-23', 33 | 'die-SIGTERM', 34 | 'die-SIGKILL', 35 | 'kill-SIGTERM', 36 | 'kill-SIGKILL', 37 | ], 38 | ) 39 | def test_child_fail(func, argv, catch, kill, exitcode): 40 | cp = ChildProcess(func, argv) 41 | ts_start = time.time() 42 | with pytest.raises(catch): 43 | cp.run() 44 | if kill is not None: 45 | os.kill(cp.pid, kill) 46 | cp.communicate(timeout=0.1) 47 | assert time.time() - ts_start < 1 48 | assert cp.exitcode == exitcode 49 | cp.close() 50 | -------------------------------------------------------------------------------- /tests/test_repo/test_minimal.py: -------------------------------------------------------------------------------- 1 | import pyroute2 2 | from pyroute2 import minimal 3 | 4 | 5 | def test_modules(): 6 | assert set(minimal.__all__) < set(pyroute2.__all__) 7 | -------------------------------------------------------------------------------- /tests/test_repo/test_version.py: -------------------------------------------------------------------------------- 1 | import io 2 | import re 3 | 4 | import pytest 5 | from packaging.version import InvalidVersion, Version 6 | 7 | 8 | @pytest.fixture 9 | def files(): 10 | context = {} 11 | for file in ('VERSION', 'CHANGELOG.rst'): 12 | with open(file, 'r') as f: 13 | obj = io.StringIO() 14 | obj.write(f.read()) 15 | obj.seek(0) 16 | context[file] = obj 17 | yield context 18 | 19 | 20 | def test_static_version_file(files): 21 | assert re.match( 22 | r'^[0-9]\.[0-9]\.[0-9]{1,2}(a[0-9]+|b[0-9]+|rc[0-9]+){0,1}$', 23 | files['VERSION'].getvalue().strip(), 24 | ) 25 | 26 | 27 | def test_changelog(files): 28 | line = '' 29 | for line in files['CHANGELOG.rst'].readlines(): 30 | if line[0] == '*': 31 | break 32 | 33 | try: 34 | static_version = Version(files['VERSION'].getvalue().strip()) 35 | last_changelog_version = Version(line.split()[1]) 36 | except InvalidVersion as e: 37 | pytest.fail(f"Invalid version encountered: {e}") 38 | 39 | assert static_version >= last_changelog_version 40 | -------------------------------------------------------------------------------- /tests/test_unit/test_addr_pool.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from pyroute2.common import AddrPool 4 | 5 | 6 | def test_alloc_aligned(): 7 | ap = AddrPool(minaddr=1, maxaddr=1024) 8 | for i in range(1024): 9 | ap.alloc() 10 | with pytest.raises(KeyError): 11 | ap.alloc() 12 | 13 | 14 | def test_alloc_odd(): 15 | ap = AddrPool(minaddr=1, maxaddr=1020) 16 | for i in range(1020): 17 | ap.alloc() 18 | with pytest.raises(KeyError): 19 | ap.alloc() 20 | 21 | 22 | def test_reverse(): 23 | ap = AddrPool(minaddr=1, maxaddr=1024, reverse=True) 24 | for i in range(512): 25 | assert ap.alloc() > ap.alloc() 26 | 27 | 28 | def test_free(): 29 | ap = AddrPool(minaddr=1, maxaddr=1024) 30 | f = ap.alloc() 31 | ap.free(f) 32 | 33 | 34 | def test_free_fail(): 35 | ap = AddrPool(minaddr=1, maxaddr=1024) 36 | with pytest.raises(KeyError): 37 | ap.free(0) 38 | 39 | 40 | def test_free_reverse_fail(): 41 | ap = AddrPool(minaddr=1, maxaddr=1024, reverse=True) 42 | with pytest.raises(KeyError): 43 | ap.free(0) 44 | 45 | 46 | def test_locate(): 47 | ap = AddrPool() 48 | f = ap.alloc() 49 | base1, bit1, is_allocated1 = ap.locate(f) 50 | base2, bit2, is_allocated2 = ap.locate(f + 1) 51 | assert base1 == base2 52 | assert bit2 == bit1 + 1 53 | assert is_allocated1 54 | assert not is_allocated2 55 | -------------------------------------------------------------------------------- /tests/test_unit/test_config.py: -------------------------------------------------------------------------------- 1 | from pyroute2 import config 2 | 3 | 4 | def test_kernel_version(): 5 | versions = { 6 | '1.2.3-test01': [1, 2, 3], 7 | '1.2.3.test01': [1, 2, 3], 8 | '10.1.12': [10, 1, 12], 9 | 'test.10.12': [], 10 | '2.10.test01': [2, 10], 11 | '5.16.5-200.fc35.x86_64': [5, 16, 5], 12 | '5.15.15.debug': [5, 15, 15], 13 | } 14 | 15 | for key, value in versions.items(): 16 | assert config.parse_kernel_version(key) == value 17 | -------------------------------------------------------------------------------- /tests/test_unit/test_entry_points/test_basic.py: -------------------------------------------------------------------------------- 1 | from pyroute2 import IPRoute 2 | from pyroute2 import NetlinkError as E1 3 | from pyroute2.netlink import NetlinkError as E2 4 | from pyroute2.netlink.exceptions import NetlinkError as E3 5 | 6 | 7 | def test_exceptions(): 8 | assert E1 == E2 == E3 9 | with IPRoute() as ipr: 10 | for e in (E1, E2, E3): 11 | try: 12 | ipr.get_links(-1) 13 | except e: 14 | pass 15 | -------------------------------------------------------------------------------- /tests/test_unit/test_nlmsg/addrmsg_ipv4.dump: -------------------------------------------------------------------------------- 1 | # pyroute2 hex dump sample 2 | # 3 | # lo: 127.0.0.1/8 4 | 4c:00:00:00:14:00:02:00:02:01:00:00:c5:4e:00:00:02:08:80:fe:01:00:00:00:08:00:01:00:7f:00:00:01:08:00:02:00:7f:00:00:01:07:00:03:00:6c:6f:00:00:08:00:08:00:80:00:00:00:14:00:06:00:ff:ff:ff:ff:ff:ff:ff:ff:05:01:00:00:05:01:00:00 5 | 6 | # parsed data should match messages below 7 | #: application/json 8 | [ 9 | { 10 | "attrs": [ 11 | [ 12 | "IFA_ADDRESS", 13 | "127.0.0.1" 14 | ], 15 | [ 16 | "IFA_LOCAL", 17 | "127.0.0.1" 18 | ], 19 | [ 20 | "IFA_LABEL", 21 | "lo" 22 | ], 23 | [ 24 | "IFA_FLAGS", 25 | 128 26 | ], 27 | [ 28 | "IFA_CACHEINFO", 29 | { 30 | "cstamp": 261, 31 | "ifa_preferred": 4294967295, 32 | "ifa_valid": 4294967295, 33 | "tstamp": 261 34 | } 35 | ] 36 | ], 37 | "event": "RTM_NEWADDR", 38 | "family": 2, 39 | "flags": 128, 40 | "header": { 41 | "error": null, 42 | "flags": 2, 43 | "length": 76, 44 | "pid": 20165, 45 | "sequence_number": 258, 46 | "type": 20 47 | }, 48 | "index": 1, 49 | "prefixlen": 8, 50 | "scope": 254 51 | } 52 | ] 53 | -------------------------------------------------------------------------------- /tests/test_unit/test_nlmsg/iw_info_rsp.dump: -------------------------------------------------------------------------------- 1 | \x58\x00\x00\x00\x1b\x00\x00\x00\x32\xfa\xdd\x54\xf2\x7b\x00\x2e\x07\x01\x00\x00\x08\x00\x03\x00\x03\x00\x00\x00\x09\x00\x04\x00\x77\x6c\x6f\x31\x00\x00\x00\x00\x08\x00\x01\x00\x00\x00\x00\x00\x08\x00\x05\x00\x02\x00\x00\x00\x0c\x00\x99\x00\x01\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x06\x00\xa4\x4e\x31\x43\x1c\x7d\x00\x00\x08\x00\x2e\x00\x05\x00\x00\x00 2 | 3 | # parsed data should match primes below 4 | #: application/json 5 | [ 6 | { 7 | "attrs": [ 8 | [ 9 | "NL80211_ATTR_IFINDEX", 10 | 3 11 | ], 12 | [ 13 | "NL80211_ATTR_IFNAME", 14 | "wlo1" 15 | ], 16 | [ 17 | "NL80211_ATTR_WIPHY", 18 | 0 19 | ], 20 | [ 21 | "NL80211_ATTR_IFTYPE", 22 | 2 23 | ], 24 | [ 25 | "NL80211_ATTR_WDEV", 26 | 1 27 | ], 28 | [ 29 | "NL80211_ATTR_MAC", 30 | "a4:4e:31:43:1c:7d" 31 | ], 32 | [ 33 | "NL80211_ATTR_GENERATION", 34 | 5 35 | ] 36 | ], 37 | "cmd": 7, 38 | "event": "NL80211_CMD_NEW_INTERFACE", 39 | "header": { 40 | "error": null, 41 | "flags": 0, 42 | "length": 88, 43 | "pid": 771783666, 44 | "sequence_number": 1423833650, 45 | "type": 27 46 | }, 47 | "reserved": 0, 48 | "version": 1 49 | } 50 | ] 51 | -------------------------------------------------------------------------------- /tests/test_unit/test_nlmsg/test_attr.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from pyroute2.netlink import nlmsg 4 | 5 | prime = { 6 | 'attrs': ( 7 | ('A', 2), 8 | ('A', 3), 9 | ('A', 4), 10 | ('B', {'attrs': (('C', 5), ('D', {'attrs': (('E', 6), ('F', 7))}))}), 11 | ) 12 | } 13 | 14 | 15 | @pytest.fixture 16 | def msg(): 17 | msg = nlmsg() 18 | msg.setvalue(prime) 19 | yield msg 20 | 21 | 22 | def test_get_attr(msg): 23 | assert msg.get_attr('A') == 2 24 | assert msg.get_attr('C') is None 25 | 26 | 27 | def test_get_attrs(msg): 28 | assert msg.get_attrs('A') == [2, 3, 4] 29 | assert msg.get_attrs('C') == [] 30 | 31 | 32 | def test_get_nested(msg): 33 | assert msg.get_nested('B', 'D', 'E') == 6 34 | assert msg.get_nested('B', 'D', 'F') == 7 35 | assert msg.get_nested('B', 'D', 'G') is None 36 | assert msg.get_nested('C', 'D', 'E') is None 37 | -------------------------------------------------------------------------------- /tests/test_unit/test_nlmsg/uevent_udevd_backlight.dump: -------------------------------------------------------------------------------- 1 | # sample 2 | 63:68:61:6e:67:65:40:2f:64:65:76:69:63:65:73:2f:70:63:69:30:30:30:30:3a:30:30 3 | 2f:30:30:30:30:3a:30:30:3a:30:32:2e:30:2f:64:72:6d:2f:63:61:72:64:30:2f:63:61 4 | 72:64:30:2d:65:44:50:2d:31:2f:69:6e:74:65:6c:5f:62:61:63:6b:6c:69:67:68:74:00 5 | 41:43:54:49:4f:4e:3d:63:68:61:6e:67:65:00:44:45:56:50:41:54:48:3d:2f:64:65:76 6 | 69:63:65:73:2f:70:63:69:30:30:30:30:3a:30:30:2f:30:30:30:30:3a:30:30:3a:30:32 7 | 2e:30:2f:64:72:6d:2f:63:61:72:64:30:2f:63:61:72:64:30:2d:65:44:50:2d:31:2f:69 8 | 6e:74:65:6c:5f:62:61:63:6b:6c:69:67:68:74:00:53:55:42:53:59:53:54:45:4d:3d:62 9 | 61:63:6b:6c:69:67:68:74:00:53:4f:55:52:43:45:3d:73:79:73:66:73:00:53:45:51:4e 10 | 55:4d:3d:31:39:33:37:32:00 11 | 12 | # parsed data should match primes below 13 | #: application/x-python-code 14 | ( 15 | { 16 | 'attrs': [], 17 | 'header': { 18 | 'sequence_number': 0, 19 | 'message': 'change@/devices/pci0000:00/0000:00:02.0/drm/card0/card0-eDP-1/intel_backlight', 20 | 'unparsed': b'' 21 | }, 22 | 'ACTION': 'change', 23 | 'DEVPATH': '/devices/pci0000:00/0000:00:02.0/drm/card0/card0-eDP-1/intel_backlight', 24 | 'SUBSYSTEM': 'backlight', 25 | 'SOURCE': 'sysfs', 26 | 'SEQNUM': '19372' 27 | }, 28 | ) 29 | -------------------------------------------------------------------------------- /tests/test_unit/test_requests/common.py: -------------------------------------------------------------------------------- 1 | from pyroute2.requests.main import RequestProcessor 2 | 3 | 4 | class Request(dict): 5 | pass 6 | 7 | 8 | class Result(dict): 9 | pass 10 | 11 | 12 | def run_test(config, spec, result): 13 | processor = RequestProcessor(context=spec, prime=spec) 14 | for fspec in config['filters']: 15 | processor.add_filter(fspec['class'](*fspec['argv'])) 16 | processor.finalize() 17 | assert Result(processor) == result 18 | -------------------------------------------------------------------------------- /tests/test_windows/test_ipr.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from pyroute2 import IPRoute 4 | 5 | 6 | @pytest.fixture 7 | def ipr(): 8 | with IPRoute() as iproute: 9 | yield iproute 10 | 11 | 12 | @pytest.mark.parametrize('variant', ('links', 'addr', 'neighbours', 'routes')) 13 | def test_list(ipr, variant): 14 | for msg in getattr(ipr, f'get_{variant}')(): 15 | assert msg['header']['target'] == 'localhost' 16 | assert msg['header']['type'] % 2 == 0 17 | -------------------------------------------------------------------------------- /util/aafigure_mapper.py: -------------------------------------------------------------------------------- 1 | import contextlib 2 | import io 3 | import sys 4 | 5 | ret = io.StringIO() 6 | 7 | with contextlib.ExitStack() as ctx: 8 | map_file = ctx.enter_context(open(sys.argv[1], 'r')) 9 | img_file = ctx.enter_context(open(sys.argv[2], 'r')) 10 | 11 | mapping = { 12 | key.strip(): value.strip() 13 | for (key, value) in [x.split('|') for x in map_file.readlines()] 14 | } 15 | for line in img_file.readlines(): 16 | if 'a href' not in line: 17 | for key, value in mapping.items(): 18 | line = line.replace(key, f' {key}') 19 | ret.write(line) 20 | 21 | with open(sys.argv[2], 'w') as img_file: 22 | img_file.write(ret.getvalue()) 23 | -------------------------------------------------------------------------------- /util/aafigure_mapper.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | find docs \ 4 | -name 'aafig-*svg' \ 5 | -exec python util/aafigure_mapper.py docs/aafigure.map '{}' \; 6 | -------------------------------------------------------------------------------- /util/find_python.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # 4 | # Utility to find Python 5 | # 6 | 7 | function list_pythons() { 8 | # 9 | # List all python binaries/shims/links in a directory $1 10 | # 11 | ls -1 $1/python* 2>/dev/null | grep -E 'python[0-9.]+$' 12 | } 13 | 14 | function check_valid_python() { 15 | # 16 | # Return "$VERSION $1" for $1 if it returns a valid version string 17 | # and has the required modules: ensurepip 18 | # 19 | # Note on versions: X.Y.Z... => XY, e.g.: 20 | # 3.6.10 -> 36 21 | # 3.10.1b1 -> 310 22 | # 23 | # This is required to sort versions correctly. The last version 24 | # byte is ignored. 25 | # 26 | for MODULE in ensurepip sqlite3; do 27 | $1 -c "import $MODULE" >/dev/null 2>&1 || return 28 | done 29 | VERSION=$( $1 -V 2>/dev/null |\ 30 | grep -E '^Python [0-9a-z.]+$' |\ 31 | sed 's/Python \([3-9]\.[0-9]\+\).*$/\1/;s/\.//' ) 32 | if [ ! -z "$VERSION" ]; then 33 | echo $VERSION $1 34 | fi 35 | } 36 | 37 | function list_valid_pythons() { 38 | # 39 | # Filter only valid Pythons in a directory $1, ignoring pyenv shims 40 | # not pointing to an installed Python binary. 41 | # 42 | for PYTHON in $( list_pythons $1 ); do 43 | PYTHON=$( check_valid_python $PYTHON ) 44 | if [ ! -z "$PYTHON" ]; then 45 | echo $PYTHON 46 | fi 47 | done 48 | } 49 | 50 | function iterate_path() { 51 | # 52 | # Iterate dirs in the $PATH variable, sorting Python versions 53 | # within each directory. 54 | # 55 | for DIR in $( echo $PATH | sed 's/:/ /g' ); do 56 | list_valid_pythons $DIR | sort -r -n 57 | done 58 | } 59 | 60 | # 61 | # Take the first available Python with the highest version, respecting 62 | # the $PATH variable. 63 | # 64 | # If operating in a venv, it will return the venv Python, despite the 65 | # higher version may be available in the system directories. 66 | # 67 | iterate_path | head -1 | cut -d \ -f 2 68 | -------------------------------------------------------------------------------- /util/imports_dict.awk: -------------------------------------------------------------------------------- 1 | /^[[:space:]]+pr2modules/ { 2 | next 3 | } 4 | 5 | /^[[:space:]]+[[:alpha:]]/ { 6 | deps[$1][key]++ 7 | } 8 | 9 | /^[[:alpha:]]+/ { 10 | key = gensub(":", "", "g", $1) 11 | } 12 | 13 | END { 14 | for (i in deps) { 15 | print(i); 16 | for (k in deps[i]) { 17 | print("\t"k); 18 | }; 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /util/update_version.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import subprocess 3 | from pathlib import Path 4 | 5 | version_module = "pyroute2/config/version.py" 6 | version_output_file = "VERSION" 7 | version_input_file = "VERSION" 8 | 9 | 10 | def get_project_version(): 11 | """ 12 | Get the project version 13 | 14 | 1. fetch version from git 15 | 2. if not available, fallback to the version file in the repo 16 | """ 17 | version = None 18 | 19 | try: 20 | git_top_level = Path( 21 | subprocess.check_output( 22 | ("git", "rev-parse", "--show-toplevel"), 23 | stderr=subprocess.DEVNULL, 24 | ) 25 | .decode("utf-8") 26 | .strip() 27 | ) 28 | pyroute2_top_level = Path(__file__).parent.parent.absolute() 29 | # Only retrieve the git description from the pyroute2 directory 30 | if git_top_level == pyroute2_top_level: 31 | version = subprocess.check_output( 32 | ("git", "describe"), stderr=subprocess.DEVNULL 33 | ).decode("utf-8") 34 | except (FileNotFoundError, subprocess.CalledProcessError): 35 | pass 36 | 37 | if version is None: 38 | with open(version_input_file, "r") as f: 39 | version = f.read() 40 | 41 | version = version.strip().split("-") 42 | 43 | if len(version) > 1: 44 | version = "{version[0]}.post{version[1]}".format(**locals()) 45 | else: 46 | version = version[0] 47 | return version 48 | 49 | 50 | if __name__ == "__main__": 51 | version = get_project_version() 52 | with open(version_module, "w") as f: 53 | f.write('__version__ = "%s"\n' % version) 54 | with open(version_output_file, "w") as f: 55 | f.write("%s\n" % version) 56 | --------------------------------------------------------------------------------