Skip to content

Commit

Permalink
Add the ability to list all neigh/local nats at once
Browse files Browse the repository at this point in the history
Removed nat-ip from required flags of list nats  and it now defaults to 0.0.0.0
  • Loading branch information
PlagueCZ committed Jan 17, 2025
1 parent d9ea4ba commit d228885
Show file tree
Hide file tree
Showing 12 changed files with 250 additions and 222 deletions.
11 changes: 5 additions & 6 deletions cli/dpservice-cli/cmd/list_nats.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,16 @@ type ListNatsOptions struct {
}

func (o *ListNatsOptions) AddFlags(fs *pflag.FlagSet) {
flag.AddrVar(fs, &o.NatIP, "nat-ip", o.NatIP, "NAT IP to get info for")
defaultAddr, err := netip.ParseAddr("0.0.0.0")
if err != nil {
defaultAddr = o.NatIP
}
flag.AddrVar(fs, &o.NatIP, "nat-ip", defaultAddr, "NAT IP to get info for")
fs.StringVar(&o.NatType, "nat-type", "0", "NAT type: Any = 0/Local = 1/Neigh(bor) = 2")
fs.StringVar(&o.SortBy, "sort-by", "", "Column to sort by.")
}

func (o *ListNatsOptions) MarkRequiredFlags(cmd *cobra.Command) error {
for _, name := range []string{"nat-ip"} {
if err := cmd.MarkFlagRequired(name); err != nil {
return err
}
}
return nil
}

Expand Down
6 changes: 3 additions & 3 deletions cli/dpservice-cli/renderer/renderer.go
Original file line number Diff line number Diff line change
Expand Up @@ -335,10 +335,10 @@ func (t defaultTableConverter) natTable(nats []api.Nat) (*TableData, error) {
var headers []any
// if command was get nat or there are no nats
if len(nats) > 0 && nats[0].InterfaceID != "" {
headers = []any{"InterfaceID", "IP", "MinPort", "MaxPort", "UnderlayRoute"}
headers = []any{"InterfaceID", "NatIP", "MinPort", "MaxPort", "UnderlayRoute"}
// if command was list nats
} else {
headers = []any{"VNI", "IP", "MinPort", "MaxPort", "UnderlayRoute", "NatType"}
headers = []any{"VNI", "IP", "MinPort", "MaxPort", "UnderlayRoute", "NatIP", "NatType"}
}

columns := make([][]any, len(nats))
Expand All @@ -348,7 +348,7 @@ func (t defaultTableConverter) natTable(nats []api.Nat) (*TableData, error) {
columns[i] = []any{nat.NatMeta.InterfaceID, nat.Spec.NatIP, nat.Spec.MinPort, nat.Spec.MaxPort, nat.Spec.UnderlayRoute}
// if command was list nats
} else {
columns[i] = []any{nat.Spec.Vni, nat.Spec.NatIP, nat.Spec.MinPort, nat.Spec.MaxPort, nat.Spec.UnderlayRoute}
columns[i] = []any{nat.Spec.Vni, nat.Spec.NatIP, nat.Spec.MinPort, nat.Spec.MaxPort, nat.Spec.UnderlayRoute, nat.Spec.ActualNatIP}
if len(nats) > 0 && nats[i].Spec.UnderlayRoute == nil {
columns[i] = append(columns[i], "Local")
} else {
Expand Down
1 change: 1 addition & 0 deletions go/dpservice-go/api/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,7 @@ type NatSpec struct {
MaxPort uint32 `json:"max_port"`
UnderlayRoute *netip.Addr `json:"underlay_route,omitempty"`
Vni uint32 `json:"vni"`
ActualNatIP *netip.Addr `json:"actual_nat_ip,omitempty"`
}

type NatList struct {
Expand Down
18 changes: 12 additions & 6 deletions go/dpservice-go/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -802,24 +802,30 @@ func (c *client) ListNats(ctx context.Context, natIP *netip.Addr, natType string
var nats = make([]api.Nat, len(natEntries))
var nat api.Nat
for i, natEntry := range natEntries {

var underlayRoute, vipIP netip.Addr
var underlayRoute, natIP, nattedIP netip.Addr
if natEntry.GetUnderlayRoute() != nil {
underlayRoute, err = netip.ParseAddr(string(natEntry.GetUnderlayRoute()))
if err != nil {
return nil, fmt.Errorf("error parsing underlay route: %w", err)
}
nat.Spec.UnderlayRoute = &underlayRoute
nat.Spec.NatIP = nil
nat.Spec.NatIP = nil // "natted" IP, i.e. local NIC IP is not applicable for neighnats
nat.Kind = api.NeighborNatKind
} else if natEntry.GetNatIp() != nil {
vipIP, err = netip.ParseAddr(string(natEntry.GetNatIp().GetAddress()))
nattedIP, err = netip.ParseAddr(string(natEntry.GetNatIp().GetAddress()))
if err != nil {
return nil, fmt.Errorf("error parsing nat ip: %w", err)
return nil, fmt.Errorf("error parsing natted ip: %w", err)
}
nat.Spec.NatIP = &vipIP
nat.Spec.NatIP = &nattedIP
nat.Kind = api.NatKind
}
if natEntry.GetActualNatIp() != nil {
natIP, err = netip.ParseAddr(string(natEntry.GetActualNatIp().GetAddress()))
if err != nil {
return nil, fmt.Errorf("error parsing nat ip: %w", err)
}
nat.Spec.ActualNatIP = &natIP
}
nat.Spec.MinPort = natEntry.MinPort
nat.Spec.MaxPort = natEntry.MaxPort
nat.Spec.Vni = natEntry.Vni
Expand Down
393 changes: 203 additions & 190 deletions go/dpservice-go/proto/dpdk.pb.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion go/dpservice-go/proto/generated_from.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v0.3.5-69-g07d470f
v0.3.14-5-g54be192
1 change: 1 addition & 0 deletions include/grpc/dp_grpc_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ struct dpgrpc_nat {
uint32_t vni; // neighnat or reply only
union dp_ipv6 neigh_addr6; // neighnat only
union dp_ipv6 ul_addr6; // reply only
struct dp_ip_address natted_ip; // list localnats reply only
};

struct dpgrpc_lb_port {
Expand Down
3 changes: 2 additions & 1 deletion proto/dpdk.proto
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,12 @@ message LbPort {
}

message NatEntry {
IpAddress nat_ip = 1;
IpAddress nat_ip = 1; // TODO This is actually the local "natted" IP
uint32 min_port = 2;
uint32 max_port = 3;
bytes underlay_route = 4;
uint32 vni = 5;
IpAddress actual_nat_ip = 6; // The actual NAT IP
}

message Route {
Expand Down
13 changes: 6 additions & 7 deletions src/dp_nat.c
Original file line number Diff line number Diff line change
Expand Up @@ -774,10 +774,6 @@ int dp_list_nat_local_entries(uint32_t nat_ip, struct dp_grpc_responder *respond
int32_t ret;
struct dpgrpc_nat *reply;

// VIP entries use the same table and have data->nat_ip set to 0 so they would match
if (nat_ip == 0)
return DP_GRPC_OK;

if (rte_hash_count(ipv4_snat_tbl) == 0)
return DP_GRPC_OK;

Expand All @@ -787,14 +783,16 @@ int dp_list_nat_local_entries(uint32_t nat_ip, struct dp_grpc_responder *respond
if (DP_FAILED(ret))
return DP_GRPC_ERR_ITERATOR;

if (data->nat_ip == nat_ip) {
// VIP entries use the same table and have data->nat_ip set to 0 so they would match when nat_ip is 0
if (data->nat_ip != 0 && (nat_ip == 0 || data->nat_ip == nat_ip)) {
reply = dp_grpc_add_reply(responder);
if (!reply)
return DP_GRPC_ERR_OUT_OF_MEMORY;
reply->min_port = data->nat_port_range[0];
reply->max_port = data->nat_port_range[1];
dp_set_ipaddr4(&reply->addr, nkey->ip);
dp_set_ipaddr4(&reply->natted_ip, nkey->ip);
reply->vni = nkey->vni;
dp_set_ipaddr4(&reply->addr, data->nat_ip);
}
}
return DP_GRPC_OK;
Expand All @@ -808,14 +806,15 @@ int dp_list_nat_neigh_entries(uint32_t nat_ip, struct dp_grpc_responder *respond
dp_grpc_set_multireply(responder, sizeof(*reply));

TAILQ_FOREACH(current, &nat_headp, entries) {
if (current->nat_ip == nat_ip) {
if (nat_ip == 0 || current->nat_ip == nat_ip) {
reply = dp_grpc_add_reply(responder);
if (!reply)
return DP_GRPC_ERR_OUT_OF_MEMORY;
reply->min_port = current->port_range[0];
reply->max_port = current->port_range[1];
reply->vni = current->vni;
dp_copy_ipv6(&reply->ul_addr6, &current->dst_ipv6);
dp_set_ipaddr4(&reply->addr, current->nat_ip);
}
}
return DP_GRPC_OK;
Expand Down
14 changes: 11 additions & 3 deletions src/grpc/dp_async_grpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -588,16 +588,20 @@ void ListLocalNatsCall::ParseReply(struct dpgrpc_reply* reply)
{
struct dpgrpc_nat *nat;
NatEntry *nat_entry;
IpAddress *natted_ip;
IpAddress *nat_ip;

FOREACH_MESSAGE(nat, reply) {
nat_entry = reply_.add_nat_entries();
nat_ip = new IpAddress();
GrpcConv::DpToGrpcAddress(&nat->addr, nat_ip);
nat_entry->set_allocated_nat_ip(nat_ip);
natted_ip = new IpAddress();
GrpcConv::DpToGrpcAddress(&nat->natted_ip, natted_ip);
nat_entry->set_allocated_nat_ip(natted_ip);
nat_entry->set_min_port(nat->min_port);
nat_entry->set_max_port(nat->max_port);
nat_entry->set_vni(nat->vni);
nat_ip = new IpAddress();
GrpcConv::DpToGrpcAddress(&nat->addr, nat_ip);
nat_entry->set_allocated_actual_nat_ip(nat_ip);
}
}

Expand Down Expand Up @@ -665,6 +669,7 @@ void ListNeighborNatsCall::ParseReply(struct dpgrpc_reply* reply)
{
struct dpgrpc_nat *nat;
NatEntry *nat_entry;
IpAddress *nat_ip;
char strbuf[INET6_ADDRSTRLEN];

FOREACH_MESSAGE(nat, reply) {
Expand All @@ -674,6 +679,9 @@ void ListNeighborNatsCall::ParseReply(struct dpgrpc_reply* reply)
nat_entry->set_min_port(nat->min_port);
nat_entry->set_max_port(nat->max_port);
nat_entry->set_vni(nat->vni);
nat_ip = new IpAddress();
GrpcConv::DpToGrpcAddress(&nat->addr, nat_ip);
nat_entry->set_allocated_actual_nat_ip(nat_ip);
}
}

Expand Down
2 changes: 1 addition & 1 deletion test/local/test_nat.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def test_network_nat_pkt_relay(prepare_ifaces, grpc_client):
assert spec == localspec, \
"Failed to add NAT properly"

neighspec = { 'underlay_route': neigh_vni1_ul_ipv6, 'min_port': nat_neigh_min_port, 'max_port': nat_neigh_max_port, 'vni': vni1 }
neighspec = { 'underlay_route': neigh_vni1_ul_ipv6, 'min_port': nat_neigh_min_port, 'max_port': nat_neigh_max_port, 'vni': vni1, 'actual_nat_ip': nat_vip }
specs = grpc_client.listneighnats(nat_vip)
assert specs == [neighspec], \
"Invalid neighboring NAT list"
Expand Down
8 changes: 4 additions & 4 deletions test/local/test_zzz_grpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,8 @@ def test_grpc_nat_list(prepare_ifaces, grpc_client):
grpc_client.addnat(VM1.name, nat_vip, nat_local_min_port, nat_local_max_port)
grpc_client.addnat(VM2.name, nat_vip, nat_local_max_port, nat_local_max_port+1)
# Local NAT list is not a list of NAT objects, need to create it manually
nat1spec = { "nat_ip": VM1.ip, "min_port": nat_local_min_port, "max_port": nat_local_max_port, "vni": VM1.vni }
nat2spec = { "nat_ip": VM2.ip, "min_port": nat_local_max_port, "max_port": nat_local_max_port+1, "vni": VM1.vni }
nat1spec = { "nat_ip": VM1.ip, "min_port": nat_local_min_port, "max_port": nat_local_max_port, "vni": VM1.vni, "actual_nat_ip": nat_vip }
nat2spec = { "nat_ip": VM2.ip, "min_port": nat_local_max_port, "max_port": nat_local_max_port+1, "vni": VM1.vni, "actual_nat_ip": nat_vip }
specs = grpc_client.listlocalnats(nat_vip)
# List order is apparently not the same as the order of operations
assert specs == [ nat2spec, nat1spec ], \
Expand Down Expand Up @@ -251,8 +251,8 @@ def test_grpc_neighnat_list(prepare_ifaces, grpc_client):
grpc_client.addneighnat(nat_vip, vni1, nat_neigh_min_port, nat_neigh_max_port, neigh_vni1_ul_ipv6)
grpc_client.addneighnat(nat_vip, vni1, nat_neigh_max_port, nat_neigh_max_port+1, neigh_vni1_ul_ipv6)
# Neighbor NAT list is not a list of NAT objects, need to create it manually
neigh1spec = { "min_port": nat_neigh_min_port, "max_port": nat_neigh_max_port, "underlay_route": neigh_vni1_ul_ipv6, "vni": vni1 }
neigh2spec = { "min_port": nat_neigh_max_port, "max_port": nat_neigh_max_port+1, "underlay_route": neigh_vni1_ul_ipv6, "vni": vni1 }
neigh1spec = { "min_port": nat_neigh_min_port, "max_port": nat_neigh_max_port, "underlay_route": neigh_vni1_ul_ipv6, "vni": vni1, "actual_nat_ip": nat_vip }
neigh2spec = { "min_port": nat_neigh_max_port, "max_port": nat_neigh_max_port+1, "underlay_route": neigh_vni1_ul_ipv6, "vni": vni1, "actual_nat_ip": nat_vip }
specs = grpc_client.listneighnats(nat_vip)
assert specs == [ neigh1spec, neigh2spec ], \
"Neighboring NATs not properly added to a list"
Expand Down

0 comments on commit d228885

Please sign in to comment.