diff options
| author | Nataliia S. <81954790+natali-rs1985@users.noreply.github.com> | 2025-05-01 20:15:32 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-05-01 18:15:32 +0100 |
| commit | 528248af9628c3170b4eac399f0bb339072d8eae (patch) | |
| tree | 5b62b4734e42fd790f1c85ea5de350400dad1212 /src/op_mode | |
| parent | f4e02fdff7a7fcb42a1c5fc313e317af63cd1dcd (diff) | |
| download | vyos-1x-528248af9628c3170b4eac399f0bb339072d8eae.tar.gz vyos-1x-528248af9628c3170b4eac399f0bb339072d8eae.zip | |
T7390: VPP CGNAT implementation (#30)
CLI:
```
set vpp nat cgnat interface outside <interface> # multi
set vpp nat cgnat interface inside <interface> # multi
set vpp nat cgnat rule <rule> outside-prefix <prefix>
set vpp nat cgnat rule <rule> inside-prefix <prefix>
set vpp nat cgnat timeout udp <sec> # default 300
set vpp nat cgnat timeout tcp-established <sec> # default 7440
set vpp nat cgnat timeout tcp-transitory <sec> # default 240
set vpp nat cgnat timeout icmp <sec> # default 60
```
OP mode:
```
show vpp nat cgnat interfaces
show vpp nat cgnat mappings
show vpp nat cgnat sessions
clear vpp cgnat inside-address <address> port <port> external-address <address> port <port>
```
Diffstat (limited to 'src/op_mode')
| -rw-r--r-- | src/op_mode/vpp_nat_cgnat.py | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/src/op_mode/vpp_nat_cgnat.py b/src/op_mode/vpp_nat_cgnat.py new file mode 100644 index 000000000..5112c70be --- /dev/null +++ b/src/op_mode/vpp_nat_cgnat.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2025 VyOS Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import json +import sys +from tabulate import tabulate + +import vyos.opmode +from vyos.configquery import ConfigTreeQuery + +from vyos.vpp import VPPControl + + +def _verify(func): + """Decorator checks if config for VPP NAT CGNAT exists""" + from functools import wraps + + @wraps(func) + def _wrapper(*args, **kwargs): + config = ConfigTreeQuery() + base = 'vpp nat cgnat' + if not config.exists(base): + raise vyos.opmode.UnconfiguredSubsystem(f'{base} is not configured') + + return func(*args, **kwargs) + + return _wrapper + + +def _get_raw_output(data_dump): + data = [json.loads(json.dumps(d._asdict(), default=str)) for d in data_dump] + return data + + +def _get_formatted_output_interfaces(vpp, interfaces): + print('CGNAT interfaces:') + for interface in interfaces: + name = vpp.get_interface_name(interface['sw_if_index']) + iface_type = 'in' if interface['is_inside'] else 'out' + print(f' {name} {iface_type}') + + +def _get_formatted_output_mappings(rules_list): + data_entries = [] + for rule in rules_list: + in_addr = rule.get('in_addr') + in_plen = str(rule.get('in_plen')) + out_addr = rule.get('out_addr') + out_plen = str(rule.get('out_plen')) + sharing_ratio = rule.get('sharing_ratio') + ports_per_host = rule.get('ports_per_host') + ses_num = rule.get('ses_num') + + values = [ + f'{in_addr}/{in_plen}', + f'{out_addr}/{out_plen}', + sharing_ratio, + ports_per_host, + ses_num, + ] + data_entries.append(values) + headers = [ + 'Inside', + 'Outside', + 'Sharing ratio', + 'Ports per host', + 'Sessions', + ] + out = sorted(data_entries, key=lambda x: x[0]) + return tabulate(out, headers=headers, tablefmt='simple') + + +@_verify +def show_sessions(raw: bool): + vpp = VPPControl() + out = vpp.cli_cmd('show det44 sessions').reply + out = out.replace('NAT44 deterministic', 'CGNAT') + return out + + +@_verify +def show_mappings(raw: bool): + vpp = VPPControl() + nat_static_dump = vpp.api.det44_map_dump() + rules_list: list[dict] = _get_raw_output(nat_static_dump) + + if raw: + return rules_list + + else: + return _get_formatted_output_mappings(rules_list) + + +@_verify +def show_interfaces(raw: bool): + vpp = VPPControl() + interfaces_dump = vpp.api.det44_interface_dump() + interfaces: list[dict] = _get_raw_output(interfaces_dump) + + if raw: + return interfaces + + else: + return _get_formatted_output_interfaces(vpp, interfaces) + + +@_verify +def clear_session(address: str, port: str, ext_address: str, ext_port: str): + vpp = VPPControl() + vpp.api.det44_close_session_in( + in_addr=address, + in_port=int(port), + ext_addr=ext_address, + ext_port=int(ext_port), + ) + + +if __name__ == '__main__': + try: + res = vyos.opmode.run(sys.modules[__name__]) + if res: + print(res) + except (ValueError, vyos.opmode.Error) as e: + print(e) + sys.exit(1) |
