syntax = "proto3";
package felix;
option go_package = "./proto";

service PolicySync {
  // On this API, only the following payloads will be sent:
  //  - InSync
  //  - IPSetUpdate
  //  - IPSetDeltaUpdate
  //  - IPSetRemove
  //  - ActiveProfileUpdate
  //  - ActiveProfileRemove
  //  - ActivePolicyUpdate
  //  - ActivePolicyRemove
  //  - WorkloadEndpointUpdate
  //  - WorkloadEndpointRemove
  //  - ServiceAccountUpdate
  //  - ServiceAccountRemove
  //  - NamespaceUpdate
  //  - NamespaceRemove
  //  - RouteUpdate
  //  - RouteRemove
  //  - VXLANTunnelEndpointUpdate
  //  - VXLANTunnelEndpointRemove
  rpc Sync(SyncRequest) returns (stream ToDataplane);

  // Report dataplane statistics to Felix.
  rpc Report(DataplaneStats) returns (ReportResult);
}

message SyncRequest {
}

// Rationale for having explicit Remove messages rather than sending and update
// with empty payload (which is the convention we used to use in Felix):
// protobuf and golang use zero values to indicate missing data and that makes
// it impossible to tell the difference between an empty list of IP set members
// and a deletion, for example.

message ToDataplane {
  // Sequence number incremented with each message.  Useful for correlating
  // messages in logs.
  uint64 sequence_number = 15;
  oneof payload {
    // InSync is sent once a complete snapshot of the datastore has been
    // processed.  The dataplane driver should use it as a signal to
    // resynchronise the dataplane.
    InSync in_sync = 1;

    // IPSetUpdate is sent when an IP set becomes active.  It contains the
    // complete membership of the IP set.
    IPSetUpdate ipset_update = 2;
    // IPSetDeltaUpdates are sent after the first IPSetUpdate; they contain
    // a list of IPs that should be added and removed from the IP set.
    IPSetDeltaUpdate ipset_delta_update = 3;
    // IPSet remove is sent when an IP set is no longer needed.
    IPSetRemove ipset_remove = 4;

    // ActiveProfileUpdate is sent when a profile becomes active or is updated.
    ActiveProfileUpdate active_profile_update = 5;
    // ActiveProfileRemove is sent when a profile becomes inactive or is
    // deleted.
    ActiveProfileRemove active_profile_remove = 6;

    // ActivePolicyUpdate is sent when a policy becomes active or is updated.
    ActivePolicyUpdate active_policy_update = 7;
    // ActivePolicyRemove is sent when a policy becomes inactive or is
    // deleted.
    ActivePolicyRemove active_policy_remove = 8;

    // HostEndpointUpdate is sent when a local host endpoint is added or
    // updated.
    HostEndpointUpdate host_endpoint_update = 9;
    // HostEndpointRemove is sent when a local host endpoint is removed.
    HostEndpointRemove host_endpoint_remove = 10;

    // WorkloadEndpointUpdate is sent when a local workload endpoint is added
    // or updated.
    WorkloadEndpointUpdate workload_endpoint_update = 11;
    // WorkloadEndpointRemove is sent when a local workload endpoint is
    // removed.
    WorkloadEndpointRemove workload_endpoint_remove = 12;

    // ConfigUpdate is sent at start of day or when the config changes.
    ConfigUpdate config_update = 13;

    // HostMetadataUpdate is sent when a host IP is added or updated.  I.e. the
    // IP used for BGP peering/IPIP.
    HostMetadataUpdate host_metadata_update = 14;
    // HostIPRemove is sent when a host IP is removed.
    HostMetadataRemove host_metadata_remove = 18;

    // HostMetadataV4V6Update is sent when a host is added or updated.
    HostMetadataV4V6Update host_metadata_v4v6_update = 37;
    // HostIPRemove is sent when a host is removed.
    HostMetadataV4V6Remove host_metadata_v4v6_remove = 38;

    // IPAMPoolUpdate is sent when an IPAM pool is added/updated.
    IPAMPoolUpdate ipam_pool_update = 16;
    // IPAMPoolRemove is sent when an IPAM pool is removed.
    IPAMPoolRemove ipam_pool_remove = 17;

    // ServiceAccountUpdate is sent when a ServiceAccount is added/updated.
    ServiceAccountUpdate service_account_update = 19;
    // ServiceAccountRemove is sent when a ServiceAccount is removed.
    ServiceAccountRemove service_account_remove = 20;

    // NamespaceUpdate is sent when a Namespace is added/updated.
    NamespaceUpdate namespace_update = 21;
    // NamespaceRemove is sent when a Namespace is removed.
    NamespaceRemove namespace_remove = 22;

    // RouteUpdate is send when a route is added/updated.
    RouteUpdate route_update = 23;
    // RouteRemove is send when a route is deleted.
    RouteRemove route_remove = 24;

    // VXLANTunnelEndpointUpdate is send when a vtep is added/updated.
    VXLANTunnelEndpointUpdate vtep_update = 25;
    // VXLANTunnelEndpointRemove is send when a route is deleted.
    VXLANTunnelEndpointRemove vtep_remove = 26;

    // WireguardEndpointUpdate is sent to setup IPv4 wireguard on the host.
    WireguardEndpointUpdate wireguard_endpoint_update = 27;
    // WireguardEndpointRemove is sent to undo IPv4 wireguard on the host.
    WireguardEndpointRemove wireguard_endpoint_remove = 28;

    // GlobalBGPConfigUpdate is sent when global BGPConfiguration changes.
    GlobalBGPConfigUpdate global_bgp_config_update = 29;

    Encapsulation encapsulation = 30;

    ServiceUpdate service_update = 31;
    ServiceRemove service_remove = 32;

    // WireguardEndpointV6Update is sent to setup IPv6 wireguard on the host.
    WireguardEndpointV6Update wireguard_endpoint_v6_update = 33;
    // WireguardEndpointV6Remove is sent to undo IPv6 wireguard on the host.
    WireguardEndpointV6Remove wireguard_endpoint_v6_remove = 34;

    // HostMetadataV6Update is sent when a host IPv6 address is added or updated.
    HostMetadataV6Update host_metadata_v6_update = 35;
    // HostMetadataV6Remove is sent when a host IPv6 address is removed.
    HostMetadataV6Remove host_metadata_v6_remove = 36;
  }
}

message FromDataplane {
  uint64 sequence_number = 8;
  oneof payload {
    // ProcessStatusUpdate is sent as a periodic heartbeat.
    ProcessStatusUpdate process_status_update = 3;

    // HostEndpointStatusUpdate is sent when the oper status of an endpoint
    // changes.
    HostEndpointStatusUpdate host_endpoint_status_update = 4;
    // HostEndpointStatusRemove is sent when an endpoint is removed to clean
    // up its oper status entry.
    HostEndpointStatusRemove host_endpoint_status_remove = 5;

    // WorkloadEndpointStatusUpdate is sent when the oper status of an endpoint
    // changes.
    WorkloadEndpointStatusUpdate workload_endpoint_status_update = 6;
    // WorkloadEndpointStatusRemove is sent when an endpoint is removed to
    // clean up its oper status entry.
    WorkloadEndpointStatusRemove workload_endpoint_status_remove = 7;

    // WireguardStatusUpdate is sent when the wireguard is available with the
    // crypto primitives set up.
    WireguardStatusUpdate wireguard_status_update = 9;

    DataplaneInSync dataplane_in_sync = 10;
  }
}

message ConfigUpdate {
  string message = 3;
  map<string, string> config = 1;
  map<uint32, RawConfig> source_to_raw_config = 2;
}

message RawConfig {
  string source = 1;
  map<string,string> config = 2;
}

message InSync {
}

message IPSetUpdate {
  string id = 1;
  repeated string members = 2;
  enum IPSetType {
    IP = 0;           // Each member is an IP address in dotted-decimal or IPv6 format.
    IP_AND_PORT = 1;  // Each member is "<IP>,(tcp|udp):port".
    NET = 2;          // Each member is a CIDR in dotted-decimal or IPv6 format.
  }
  IPSetType type = 3;
}

message IPSetDeltaUpdate {
  string id = 1;
  repeated string added_members = 2;
  repeated string removed_members = 3;
}

message IPSetRemove {
  string id = 1;
}

message ActiveProfileUpdate {
  ProfileID id = 1;
  Profile profile = 2;
}

message ActiveProfileRemove {
  ProfileID id = 1;
}

message ProfileID {
  string name = 1;
}

message Profile {
  repeated Rule inbound_rules = 1;
  repeated Rule outbound_rules = 2;
}

message ActivePolicyUpdate {
  PolicyID id = 1;
  Policy policy = 2;
}

message ActivePolicyRemove {
  PolicyID id = 1;
}

message PolicyID {
  // The "tier" field has been deprecated and removed.
  reserved 1;
  reserved "tier";

  string name = 2;
  string namespace = 3;
  string kind = 4;
}

message Policy {
  // If the Policy represents a NetworkPolicy, this contains the namespace that the policy came
  // from.  Otherwise, empty.
  string namespace = 5;

  repeated Rule inbound_rules = 1;
  repeated Rule outbound_rules = 2;
  bool untracked = 3;
  bool pre_dnat = 4;

  string original_selector = 6;

  repeated string perf_hints = 7;

  string tier = 8;
}

enum IPVersion {
  ANY = 0;
  IPV4 = 4;
  IPV6 = 6;
}

message Rule {
  string action = 1;
  IPVersion ip_version = 2;

  Protocol protocol = 3;

  repeated string src_net = 4;

  // The list of ports is split into numeric and named ports, where named ports are represented
  // by (IP, port) IP sets.  A packet matches this rule if it matches any numeric port range *or*
  // any listed named port IP set.
  repeated PortRange src_ports = 5;
  repeated string src_named_port_ip_set_ids = 12;

  repeated string dst_net = 6;
  repeated PortRange dst_ports = 7;
  repeated string dst_named_port_ip_set_ids = 13;
  oneof icmp {
    // Distinguish between a match on type only and type+code.  We can't use
    // the fact that fields ar optional because Go can't distinguish 0 from
    // "not-present".
    int32 icmp_type = 8;
    IcmpTypeAndCode icmp_type_code = 9;
  }
  repeated string src_ip_set_ids = 10;
  repeated string dst_ip_set_ids = 11;

  // IP sets on which we should match both IP and port.
  repeated string dst_ip_port_set_ids = 15;

  Protocol not_protocol = 102;

  repeated string not_src_net = 103;
  repeated PortRange not_src_ports = 104;
  repeated string not_dst_net = 105;
  repeated PortRange not_dst_ports = 106;
  oneof not_icmp {
    int32 not_icmp_type = 107;
    IcmpTypeAndCode not_icmp_type_code = 108;
  }
  repeated string not_src_ip_set_ids = 109;
  repeated string not_dst_ip_set_ids = 110;
  repeated string not_src_named_port_ip_set_ids = 112;
  repeated string not_dst_named_port_ip_set_ids = 113;

  // These fields pass through the original selectors from the v3 datamodel unmodified as required
  // for the policy sync API.
  string original_src_selector = 114;
  string original_dst_selector = 115;
  string original_src_namespace_selector = 116;
  string original_dst_namespace_selector = 117;
  string original_not_src_selector = 118;
  string original_not_dst_selector = 119;

  // Original source service match criteria.
  string original_src_service = 132;
  string original_src_service_namespace = 133;

  // Original destination service match criteria.
  string original_dst_service = 130;
  string original_dst_service_namespace = 131;

  // Pass through of the v3 datamodel service account match criteria.
  ServiceAccountMatch src_service_account_match = 120;
  ServiceAccountMatch dst_service_account_match = 121;

  // Pass through of the v3 datamodel HTTP match criteria.
  HTTPMatch http_match = 122;

  RuleMetadata metadata = 123;

  // Changed to FelixConfig option.
  reserved 200;
  reserved "log_prefix";

  // An opaque ID/hash for the rule.
  string rule_id = 201;
}

message ServiceAccountMatch {
  string selector = 1;
  repeated string names = 2;
}

message HTTPMatch {
  repeated string methods = 1;
  message PathMatch {
    oneof path_match {
      string exact = 1;
      string prefix = 2;
    }
  }
  repeated PathMatch paths = 2;
}

message RuleMetadata {
  map<string, string> annotations = 1;
}

message IcmpTypeAndCode {
  int32 type = 1;
  int32 code = 2;
}

message Protocol {
  oneof number_or_name {
    int32 number = 1;
    string name = 2;
  }
}

// Individual ports are sent with first == last.
message PortRange {
  int32 first = 1;
  int32 last = 2;
}

message WorkloadEndpointID {
  // hostname not needed since this is implicitly a local endpoint?
  reserved 1;
  reserved "hostname";

  string orchestrator_id = 2;
  string workload_id = 3;
  string endpoint_id = 4;
}

message WorkloadEndpointUpdate {
  WorkloadEndpointID id = 1;
  WorkloadEndpoint endpoint = 5;
}

message WorkloadBpfSkipRedir {
  bool Egress = 1;
  bool Ingress = 2;
}

enum LiveMigrationRole {
  NO_ROLE = 0;
  SOURCE = 1;
  TARGET = 2;
}

message WorkloadEndpoint {
  string state = 1;
  string name = 2;
  string mac = 3;
  repeated string profile_ids = 4;
  repeated string ipv4_nets = 5;
  repeated string ipv6_nets = 6;
  repeated TierInfo tiers = 7;
  repeated NatInfo ipv4_nat = 8;
  repeated NatInfo ipv6_nat = 9;
  repeated string allow_spoofed_source_prefixes = 10;
  map<string, string> annotations = 11;
  QoSControls qos_controls = 12;
  LocalBGPPeer local_bgp_peer = 13;
  WorkloadBpfSkipRedir skip_redir = 14;
  repeated QoSPolicy qos_policies = 15;
  bool is_istio_ambient = 16;
  LiveMigrationRole live_migration_role = 17;
  string live_migration_uid = 18;
  string live_migration_vmi_name = 19;
}

message QoSControls {
  int64 IngressBandwidth      = 1;
  int64 EgressBandwidth       = 2;
  int64 IngressBurst          = 3;
  int64 EgressBurst           = 4;
  int64 IngressPacketRate     = 5;
  int64 EgressPacketRate      = 6;
  int64 IngressMaxConnections = 7;
  int64 EgressMaxConnections  = 8;
  int64 IngressPeakrate       = 9;
  int64 EgressPeakrate        = 10;
  int64 IngressMinburst       = 11;
  int64 EgressMinburst        = 12;
  int64 IngressPacketBurst    = 13;
  int64 EgressPacketBurst     = 14;
}

message QoSPolicy {
  string destination = 1;
  int32 dscp = 2;
}

message LocalBGPPeer {
  string bgp_peer_name = 1;
}

message WorkloadEndpointRemove {
  WorkloadEndpointID id = 1;
}

message HostEndpointID {
  // hostname not needed since this is implicitly a local endpoint?
  reserved 1;
  reserved "hostname";
  string endpoint_id = 2;
}

message HostEndpointUpdate {
  HostEndpointID id = 1;
  HostEndpoint endpoint = 3;
}

message HostEndpoint {
  string name = 1;
  repeated string profile_ids = 2;
  repeated TierInfo tiers = 3;
  repeated TierInfo untracked_tiers = 6;
  repeated TierInfo pre_dnat_tiers = 7;
  repeated TierInfo forward_tiers = 8;
  repeated string expected_ipv4_addrs = 4;
  repeated string expected_ipv6_addrs = 5;
  repeated QoSPolicy qos_policies = 9;
}

message HostEndpointRemove {
  HostEndpointID id = 1;
}

message TierInfo {
  string name = 1;
  repeated PolicyID ingress_policies = 2;
  repeated PolicyID egress_policies = 3;
  string default_action = 4;
}

message NatInfo {
  string ext_ip = 1;
  string int_ip = 2;
}

message ProcessStatusUpdate {
  string iso_timestamp = 1;
  double uptime = 2;
}

message HostEndpointStatusUpdate {
  HostEndpointID id = 1;
  EndpointStatus status = 2;
}

message EndpointStatus {
  string status = 1;
}

message HostEndpointStatusRemove {
  HostEndpointID id = 1;
}

message WorkloadEndpointStatusUpdate {
  WorkloadEndpointID id = 1;
  EndpointStatus status = 2;
  WorkloadEndpoint endpoint = 3;
}
message WorkloadEndpointStatusRemove {
  WorkloadEndpointID id = 1;
}

message WireguardStatusUpdate {
  // Wireguard public-key set on the interface.
  string public_key = 1;

  // The IP version of this update
  IPVersion ip_version = 2;
}

message DataplaneInSync {
}

message HostMetadataV4V6Update {
  string hostname = 1;
  string ipv4_addr = 2;
  string ipv6_addr = 3;
  string asnumber = 4;
  map<string, string> labels = 5;
}

message HostMetadataV4V6Remove {
  string hostname = 1;
  string ipv4_addr = 2;
}

message HostMetadataUpdate {
  string hostname = 1;
  string ipv4_addr = 2;
}

message HostMetadataRemove {
  string hostname = 1;
  string ipv4_addr = 2;
}

message HostMetadataV6Update {
  string hostname = 1;
  string ipv6_addr = 2;
}

message HostMetadataV6Remove {
  string hostname = 1;
  string ipv6_addr = 2;
}

message IPAMPoolUpdate {
  string id = 1;
  IPAMPool pool = 2;
}

message IPAMPoolRemove {
  string id = 1;
}

message IPAMPool {
  string cidr = 1;
  bool masquerade = 2;
  string ipip_mode = 3;
  string vxlan_mode = 4;
  repeated string allowed_uses = 5;
}

message Encapsulation {
  bool ipip_enabled = 1;
  bool vxlan_enabled = 2;
  bool vxlan_enabled_v6 = 3;
}

message ServiceAccountUpdate {
  ServiceAccountID id = 1;
  map<string, string> labels = 2;
}

message ServiceAccountRemove {
  ServiceAccountID id = 1;
}

message ServiceAccountID {
  string namespace = 1;
  string name = 2;
}

message NamespaceUpdate {
  NamespaceID id = 1;
  map<string, string> labels = 2;
}

message NamespaceRemove {
  NamespaceID id = 1;
}

message NamespaceID {
  string name = 1;
}

// RouteTYpe defines a type of route. Each is a power of 2, so that theye can be used as
// unique bits within a bitmap.
enum RouteType {
  // CIDR_INFO gives information about a CIDR without establishing a route.  For example,
  // it is emitted for IP pools with no blocks.
  CIDR_INFO = 0;
  REMOTE_WORKLOAD = 1;
  REMOTE_HOST = 2;
  LOCAL_WORKLOAD = 4;
  LOCAL_HOST = 8;
  REMOTE_TUNNEL = 16;
  LOCAL_TUNNEL = 32;
}

enum IPPoolType {
  NONE = 0;
  NO_ENCAP = 1;
  VXLAN = 2;
  IPIP = 3;
}

message TunnelType {
  bool ipip = 1;
  bool vxlan = 2;
  bool wireguard = 3;
}

message RouteUpdate {
  // The "type" field has been deprecated and removed in favor of "types".
  reserved 1;
  reserved "type";

  // Types is a bitmap field indicating which route types apply to this route.
  RouteType types = 12;

  IPPoolType ip_pool_type = 2;
  string dst = 3;
  // The name of the node holding this destination, if this route targets a calico node.
  string dst_node_name = 4;
  // IP of the node holding this destination.
  string dst_node_ip = 5;
  bool same_subnet = 7;
  bool nat_outgoing = 8;
  bool local_workload = 9;
  TunnelType tunnel_type = 10;
  bool borrowed = 11;
}

message RouteRemove {
  string dst = 2;
}

message VXLANTunnelEndpointUpdate {
  string node = 1;
  string mac = 2;
  string ipv4_addr = 3;
  string parent_device_ip = 4;
  string mac_v6 = 5;
  string ipv6_addr = 6;
  string parent_device_ipv6 = 7;
}

message VXLANTunnelEndpointRemove {
  string node = 1;
}

message ReportResult {
  // Whether the data was reported successfully.
  bool successful = 1;
}

// DataplaneStats reports statistics about a flow from the dataplane.
message DataplaneStats {
  // Identity of the flow.
  // Right now, just 5-tuple
  string src_ip = 1;
  string dst_ip = 2;
  int32 src_port = 3;
  int32 dst_port = 4;
  Protocol protocol = 5;

  // Each message can report zero or more statistics about the flow.
  repeated Statistic stats = 6;

  // RuleTrace is the sequence of rules that matched the flow. The last rule
  // allows or denies the flow, each rule prior "passed" to the next tier or
  // to profiles.
  repeated RuleTrace rules = 7;

  // Whether the flow was allowed or denied
  Action action = 8;
}

// Action represents an action taken by a policy or rule.
enum Action {
  ALLOWED = 0;
  DENIED = 1;
}

// Statistic is a piece of summary information for a flow.
message Statistic {

  // Whether the statistic is for inbound or outbound data flow, relative to
  // the dataplane reporting.
  enum Direction {
    IN = 0;
    OUT = 1;
  }
  Direction direction = 1;

  // Whether the data is relative. ABSOLUTE data gives the total for the flow
  // since it started.  DELTA data gives the change since the last report
  // for this flow.
  enum Relativity {
    ABSOLUTE = 0;
    DELTA = 1;
  }
  Relativity relativity = 2;

  // Kind indicates what this statistic is about.
  enum Kind {
    PACKETS = 0;
    BYTES = 1;
  }
  Kind kind = 3;

  // Action further qualifies the kind.  For example, an action of ALLOWED with
  // a kind of PACKETS means this statistic is the number of allowed packets.
  Action action = 4;

  // The numerical value of the statistic.
  int64 value = 5;
}

// RuleTrace indicates a rule that matched the flow as it was being evaluated.
message RuleTrace {
  oneof id {
    // The rule is part of a policy identified in this field.
    PolicyID policy = 1;

    // The rule is part of a profile identified in this field.
    ProfileID profile = 2;

    // The flow was neither allowed nor denied by any policy or profile.  By
    // default this means the flow is denied. If this is set the rule num should
    // be ignored since no rule matched the flow.
    bool none = 3;
  }

  // Whether the rule appears in INBOUND or OUTBOUND rules for the policy /
  // profile.
  enum Direction {
    INBOUND = 0;
    OUTBOUND = 1;
  }
  Direction direction = 4;

  // The numerical index of the rule that matched.
  int32 rule_num = 5;
}

message WireguardEndpointUpdate {
  // The name of the IPv4 wireguard host.
  string hostname = 1;

  // The public key for IPv4 wireguard on this endpoint.
  string public_key = 2;

  // The IP address of the IPv4 wireguard interface.
  string interface_ipv4_addr = 3;
}

message WireguardEndpointRemove {
  // The name of the IPv4 wireguard host.
  string hostname = 1;
}

message WireguardEndpointV6Update {
  // The name of the IPv6 wireguard host.
  string hostname = 1;

  // The public key for IPv6 wireguard on this endpoint.
  string public_key_v6 = 2;

  // The IP address of the IPv6 wireguard interface.
  string interface_ipv6_addr = 3;
}

message WireguardEndpointV6Remove {
  // The name of the IPv6 wireguard host.
  string hostname = 1;
}

message GlobalBGPConfigUpdate {
  repeated string service_cluster_cidrs = 1;
  repeated string service_external_cidrs = 2;
  repeated string service_loadbalancer_cidrs = 3;
  string local_workload_peering_ip_v4 = 4;
  string local_workload_peering_ip_v6 = 5;
}

message ServicePort {
	string Protocol = 1;
	int32 Port = 2;
	int32 NodePort = 3;
}

message ServiceUpdate {
	string name = 1;
	string namespace = 2;
	string type = 3;
	repeated string cluster_ips = 4;
	string loadbalancer_ip = 5;
	repeated string external_ips = 6;
	repeated ServicePort ports = 7;
}

message ServiceRemove {
	string name = 1;
	string namespace = 2;
}
