ipsec: change wildcard value for any protocol of spd policy

Currently 0 has been used as the wildcard representing ANY type of
protocol. However 0 is valid value of ip protocol (HOPOPT) and therefore
it should not be used as a wildcard. Instead 255 is used which is
guaranteed by IANA to be reserved and not used as a protocol id.

Type: improvement
Signed-off-by: Piotr Bronowski <piotrx.bronowski@intel.com>
Change-Id: I2320bae6fe380cb999dc5a9187beb68fda2d31eb
diff --git a/src/vnet/ipsec/ipsec.api b/src/vnet/ipsec/ipsec.api
index be45c3e..18df893 100644
--- a/src/vnet/ipsec/ipsec.api
+++ b/src/vnet/ipsec/ipsec.api
@@ -57,61 +57,6 @@
   u32 spd_id;
 };
 
-
-enum ipsec_spd_action
-{
-  /* bypass - no IPsec processing */
-  IPSEC_API_SPD_ACTION_BYPASS = 0,
-  /* discard - discard packet with ICMP processing */
-  IPSEC_API_SPD_ACTION_DISCARD,
-  /* resolve - send request to control plane for SA resolving */
-  IPSEC_API_SPD_ACTION_RESOLVE,
-  /* protect - apply IPsec policy using following parameters */
-  IPSEC_API_SPD_ACTION_PROTECT,
-};
-
-/** \brief IPsec: Security Policy Database entry
-
-    See RFC 4301, 4.4.1.1 on how to match packet to selectors
-
-    @param spd_id - SPD instance id (control plane allocated)
-    @param priority - priority of SPD entry (non-unique value).  Used to order SPD matching - higher priorities match before lower
-    @param is_outbound - entry applies to outbound traffic if non-zero, otherwise applies to inbound traffic
-    @param remote_address_start - start of remote address range to match
-    @param remote_address_stop - end of remote address range to match
-    @param local_address_start - start of local address range to match
-    @param local_address_stop - end of local address range to match
-    @param protocol - protocol type to match [0 means any] otherwise IANA value
-    @param remote_port_start - start of remote port range to match ...
-    @param remote_port_stop - end of remote port range to match [0 to 65535 means ANY, 65535 to 0 means OPAQUE]
-    @param local_port_start - start of local port range to match ...
-    @param local_port_stop - end of remote port range to match [0 to 65535 means ANY, 65535 to 0 means OPAQUE]
-    @param policy - action to perform on match
-    @param sa_id - SAD instance id (control plane allocated)
-*/
-typedef ipsec_spd_entry
-{
-  u32 spd_id;
-  i32 priority;
-  bool is_outbound;
-
-  u32 sa_id;
-  vl_api_ipsec_spd_action_t policy;
-  /* Which protocol?? */
-  u8 protocol;
-
-  // Selector
-  vl_api_address_t remote_address_start;
-  vl_api_address_t remote_address_stop;
-  vl_api_address_t local_address_start;
-  vl_api_address_t local_address_stop;
-
-  u16 remote_port_start;
-  u16 remote_port_stop;
-  u16 local_port_start;
-  u16 local_port_stop;
-};
-
 /** \brief IPsec: Add/delete Security Policy Database entry
 
     @param client_index - opaque cookie to identify the sender
@@ -121,12 +66,28 @@
 */
 define ipsec_spd_entry_add_del
 {
+  option deprecated;
   u32 client_index;
   u32 context;
   bool is_add;
   vl_api_ipsec_spd_entry_t entry;
 };
 
+/** \brief IPsec: Add/delete Security Policy Database entry v2
+
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param is_add - add SPD if non-zero, else delete
+    @param entry - Description of the entry to add/dell
+*/
+define ipsec_spd_entry_add_del_v2
+{
+  u32 client_index;
+  u32 context;
+  bool is_add;
+  vl_api_ipsec_spd_entry_v2_t entry;
+};
+
 /** \brief IPsec: Reply Add/delete Security Policy Database entry
 
     @param context - sender context, to match reply w/ request
@@ -140,6 +101,19 @@
   u32 stat_index;
 };
 
+/** \brief IPsec: Reply Add/delete Security Policy Database entry v2
+
+    @param context - sender context, to match reply w/ request
+    @param retval - success/fail rutrun code
+    @param stat_index - An index for the policy in the stats segment @ /net/ipec/policy
+*/
+define ipsec_spd_entry_add_del_v2_reply
+{
+  u32 context;
+  i32 retval;
+  u32 stat_index;
+};
+
 /** \brief Dump IPsec all SPD IDs
     @param client_index - opaque cookie to identify the sender
     @param context - sender context, to match reply w/ request
@@ -197,6 +171,7 @@
   bool is_add;
   vl_api_ipsec_sad_entry_t entry;
 };
+
 define ipsec_sad_entry_add_del_v2
 {
   u32 client_index;
@@ -204,6 +179,7 @@
   bool is_add;
   vl_api_ipsec_sad_entry_v2_t entry;
 };
+
 define ipsec_sad_entry_add_del_v3
 {
   u32 client_index;
@@ -231,12 +207,14 @@
   i32 retval;
   u32 stat_index;
 };
+
 define ipsec_sad_entry_add_del_v2_reply
 {
   u32 context;
   i32 retval;
   u32 stat_index;
 };
+
 define ipsec_sad_entry_add_del_v3_reply
 {
   u32 context;
diff --git a/src/vnet/ipsec/ipsec_api.c b/src/vnet/ipsec/ipsec_api.c
index 72231f6..15f7bfa 100644
--- a/src/vnet/ipsec/ipsec_api.c
+++ b/src/vnet/ipsec/ipsec_api.c
@@ -233,7 +233,8 @@
 
   p.is_ipv6 = (itype == IP46_TYPE_IP6);
 
-  p.protocol = mp->entry.protocol;
+  p.protocol =
+    mp->entry.protocol ? mp->entry.protocol : IPSEC_POLICY_PROTOCOL_ANY;
   p.rport.start = ntohs (mp->entry.remote_port_start);
   p.rport.stop = ntohs (mp->entry.remote_port_stop);
   p.lport.start = ntohs (mp->entry.local_port_start);
@@ -271,6 +272,65 @@
   /* *INDENT-ON* */
 }
 
+static void
+vl_api_ipsec_spd_entry_add_del_v2_t_handler (
+  vl_api_ipsec_spd_entry_add_del_v2_t *mp)
+{
+  vlib_main_t *vm __attribute__ ((unused)) = vlib_get_main ();
+  vl_api_ipsec_spd_entry_add_del_reply_t *rmp;
+  ip46_type_t itype;
+  u32 stat_index;
+  int rv;
+
+  stat_index = ~0;
+
+  ipsec_policy_t p;
+
+  clib_memset (&p, 0, sizeof (p));
+
+  p.id = ntohl (mp->entry.spd_id);
+  p.priority = ntohl (mp->entry.priority);
+
+  itype = ip_address_decode (&mp->entry.remote_address_start, &p.raddr.start);
+  ip_address_decode (&mp->entry.remote_address_stop, &p.raddr.stop);
+  ip_address_decode (&mp->entry.local_address_start, &p.laddr.start);
+  ip_address_decode (&mp->entry.local_address_stop, &p.laddr.stop);
+
+  p.is_ipv6 = (itype == IP46_TYPE_IP6);
+
+  p.protocol = mp->entry.protocol;
+  p.rport.start = ntohs (mp->entry.remote_port_start);
+  p.rport.stop = ntohs (mp->entry.remote_port_stop);
+  p.lport.start = ntohs (mp->entry.local_port_start);
+  p.lport.stop = ntohs (mp->entry.local_port_stop);
+
+  rv = ipsec_spd_action_decode (mp->entry.policy, &p.policy);
+
+  if (rv)
+    goto out;
+
+  /* policy action resolve unsupported */
+  if (p.policy == IPSEC_POLICY_ACTION_RESOLVE)
+    {
+      clib_warning ("unsupported action: 'resolve'");
+      rv = VNET_API_ERROR_UNIMPLEMENTED;
+      goto out;
+    }
+  p.sa_id = ntohl (mp->entry.sa_id);
+  rv =
+    ipsec_policy_mk_type (mp->entry.is_outbound, p.is_ipv6, p.policy, &p.type);
+  if (rv)
+    goto out;
+
+  rv = ipsec_add_del_policy (vm, &p, mp->is_add, &stat_index);
+  if (rv)
+    goto out;
+
+out:
+  REPLY_MACRO2 (VL_API_IPSEC_SPD_ENTRY_ADD_DEL_REPLY,
+		({ rmp->stat_index = ntohl (stat_index); }));
+}
+
 static void vl_api_ipsec_sad_entry_add_del_t_handler
   (vl_api_ipsec_sad_entry_add_del_t * mp)
 {
diff --git a/src/vnet/ipsec/ipsec_cli.c b/src/vnet/ipsec/ipsec_cli.c
index df8f937..8b436b6 100644
--- a/src/vnet/ipsec/ipsec_cli.c
+++ b/src/vnet/ipsec/ipsec_cli.c
@@ -279,6 +279,7 @@
   clib_memset (&p, 0, sizeof (p));
   p.lport.stop = p.rport.stop = ~0;
   remote_range_set = local_range_set = is_outbound = 0;
+  p.protocol = IPSEC_POLICY_PROTOCOL_ANY;
 
   if (!unformat_user (input, unformat_line_input, line_input))
     return 0;
diff --git a/src/vnet/ipsec/ipsec_format.c b/src/vnet/ipsec/ipsec_format.c
index c8c0170..24c9bee 100644
--- a/src/vnet/ipsec/ipsec_format.c
+++ b/src/vnet/ipsec/ipsec_format.c
@@ -168,7 +168,7 @@
 	      pi, p->priority,
 	      format_ipsec_policy_action, p->policy,
 	      format_ipsec_policy_type, p->type);
-  if (p->protocol)
+  if (p->protocol != IPSEC_POLICY_PROTOCOL_ANY)
     {
       s = format (s, "%U", format_ip_protocol, p->protocol);
     }
diff --git a/src/vnet/ipsec/ipsec_output.c b/src/vnet/ipsec/ipsec_output.c
index 6d6608d..760d092 100644
--- a/src/vnet/ipsec/ipsec_output.c
+++ b/src/vnet/ipsec/ipsec_output.c
@@ -158,7 +158,8 @@
   vec_foreach (i, spd->policies[IPSEC_SPD_POLICY_IP4_OUTBOUND])
   {
     p = pool_elt_at_index (im->policies, *i);
-    if (PREDICT_FALSE (p->protocol && (p->protocol != pr)))
+    if (PREDICT_FALSE ((p->protocol != IPSEC_POLICY_PROTOCOL_ANY) &&
+		       (p->protocol != pr)))
       continue;
 
     if (ra < clib_net_to_host_u32 (p->raddr.start.ip4.as_u32))
@@ -232,7 +233,8 @@
   vec_foreach (i, spd->policies[IPSEC_SPD_POLICY_IP6_OUTBOUND])
   {
     p = pool_elt_at_index (im->policies, *i);
-    if (PREDICT_FALSE (p->protocol && (p->protocol != pr)))
+    if (PREDICT_FALSE ((p->protocol != IPSEC_POLICY_PROTOCOL_ANY) &&
+		       (p->protocol != pr)))
       continue;
 
     if (!ip6_addr_match_range (ra, &p->raddr.start.ip6, &p->raddr.stop.ip6))
diff --git a/src/vnet/ipsec/ipsec_spd_policy.h b/src/vnet/ipsec/ipsec_spd_policy.h
index 6d6b695..fc9c23a 100644
--- a/src/vnet/ipsec/ipsec_spd_policy.h
+++ b/src/vnet/ipsec/ipsec_spd_policy.h
@@ -17,6 +17,8 @@
 
 #include <vnet/ipsec/ipsec_spd.h>
 
+#define IPSEC_POLICY_PROTOCOL_ANY IP_PROTOCOL_RESERVED
+
 #define foreach_ipsec_policy_action \
   _ (0, BYPASS, "bypass")           \
   _ (1, DISCARD, "discard")         \
diff --git a/src/vnet/ipsec/ipsec_test.c b/src/vnet/ipsec/ipsec_test.c
index f3a9992..f143619 100644
--- a/src/vnet/ipsec/ipsec_test.c
+++ b/src/vnet/ipsec/ipsec_test.c
@@ -73,7 +73,103 @@
   unformat_input_t *i = vam->input;
   vl_api_ipsec_spd_entry_add_del_t *mp;
   u8 is_add = 1, is_outbound = 0;
-  u32 spd_id = 0, sa_id = 0, protocol = 0, policy = 0;
+  u32 spd_id = 0, sa_id = 0, protocol = IPSEC_POLICY_PROTOCOL_ANY, policy = 0;
+  i32 priority = 0;
+  u32 rport_start = 0, rport_stop = (u32) ~0;
+  u32 lport_start = 0, lport_stop = (u32) ~0;
+  vl_api_address_t laddr_start = {}, laddr_stop = {}, raddr_start = {},
+		   raddr_stop = {};
+  int ret;
+
+  while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (i, "del"))
+	is_add = 0;
+      if (unformat (i, "outbound"))
+	is_outbound = 1;
+      if (unformat (i, "inbound"))
+	is_outbound = 0;
+      else if (unformat (i, "spd_id %d", &spd_id))
+	;
+      else if (unformat (i, "sa_id %d", &sa_id))
+	;
+      else if (unformat (i, "priority %d", &priority))
+	;
+      else if (unformat (i, "protocol %d", &protocol))
+	;
+      else if (unformat (i, "lport_start %d", &lport_start))
+	;
+      else if (unformat (i, "lport_stop %d", &lport_stop))
+	;
+      else if (unformat (i, "rport_start %d", &rport_start))
+	;
+      else if (unformat (i, "rport_stop %d", &rport_stop))
+	;
+      else if (unformat (i, "laddr_start %U", unformat_vl_api_address,
+			 &laddr_start))
+	;
+      else if (unformat (i, "laddr_stop %U", unformat_vl_api_address,
+			 &laddr_stop))
+	;
+      else if (unformat (i, "raddr_start %U", unformat_vl_api_address,
+			 &raddr_start))
+	;
+      else if (unformat (i, "raddr_stop %U", unformat_vl_api_address,
+			 &raddr_stop))
+	;
+      else if (unformat (i, "action %U", unformat_ipsec_policy_action,
+			 &policy))
+	{
+	  if (policy == IPSEC_POLICY_ACTION_RESOLVE)
+	    {
+	      clib_warning ("unsupported action: 'resolve'");
+	      return -99;
+	    }
+	}
+      else
+	{
+	  clib_warning ("parse error '%U'", format_unformat_error, i);
+	  return -99;
+	}
+    }
+
+  M (IPSEC_SPD_ENTRY_ADD_DEL, mp);
+
+  mp->is_add = is_add;
+
+  mp->entry.spd_id = ntohl (spd_id);
+  mp->entry.priority = ntohl (priority);
+  mp->entry.is_outbound = is_outbound;
+
+  clib_memcpy (&mp->entry.remote_address_start, &raddr_start,
+	       sizeof (vl_api_address_t));
+  clib_memcpy (&mp->entry.remote_address_stop, &raddr_stop,
+	       sizeof (vl_api_address_t));
+  clib_memcpy (&mp->entry.local_address_start, &laddr_start,
+	       sizeof (vl_api_address_t));
+  clib_memcpy (&mp->entry.local_address_stop, &laddr_stop,
+	       sizeof (vl_api_address_t));
+
+  mp->entry.protocol = protocol ? (u8) protocol : IPSEC_POLICY_PROTOCOL_ANY;
+  mp->entry.local_port_start = ntohs ((u16) lport_start);
+  mp->entry.local_port_stop = ntohs ((u16) lport_stop);
+  mp->entry.remote_port_start = ntohs ((u16) rport_start);
+  mp->entry.remote_port_stop = ntohs ((u16) rport_stop);
+  mp->entry.policy = (u8) policy;
+  mp->entry.sa_id = ntohl (sa_id);
+
+  S (mp);
+  W (ret);
+  return ret;
+}
+
+static int
+api_ipsec_spd_entry_add_del_v2 (vat_main_t *vam)
+{
+  unformat_input_t *i = vam->input;
+  vl_api_ipsec_spd_entry_add_del_t *mp;
+  u8 is_add = 1, is_outbound = 0;
+  u32 spd_id = 0, sa_id = 0, protocol = IPSEC_POLICY_PROTOCOL_ANY, policy = 0;
   i32 priority = 0;
   u32 rport_start = 0, rport_stop = (u32) ~0;
   u32 lport_start = 0, lport_stop = (u32) ~0;
@@ -257,6 +353,12 @@
 {
 }
 
+static void
+vl_api_ipsec_spd_entry_add_del_v2_reply_t_handler (
+  vl_api_ipsec_spd_entry_add_del_v2_reply_t *mp)
+{
+}
+
 static int
 api_ipsec_spds_dump (vat_main_t *vam)
 {
diff --git a/src/vnet/ipsec/ipsec_types.api b/src/vnet/ipsec/ipsec_types.api
index ed04f47..fd7068e 100644
--- a/src/vnet/ipsec/ipsec_types.api
+++ b/src/vnet/ipsec/ipsec_types.api
@@ -95,6 +95,102 @@
   u8 data[128];
 };
 
+enum ipsec_spd_action
+{
+  /* bypass - no IPsec processing */
+  IPSEC_API_SPD_ACTION_BYPASS = 0,
+  /* discard - discard packet with ICMP processing */
+  IPSEC_API_SPD_ACTION_DISCARD,
+  /* resolve - send request to control plane for SA resolving */
+  IPSEC_API_SPD_ACTION_RESOLVE,
+  /* protect - apply IPsec policy using following parameters */
+  IPSEC_API_SPD_ACTION_PROTECT,
+};
+
+/** \brief IPsec: Security Policy Database entry
+
+    See RFC 4301, 4.4.1.1 on how to match packet to selectors
+
+    @param spd_id - SPD instance id (control plane allocated)
+    @param priority - priority of SPD entry (non-unique value).  Used to order SPD matching - higher priorities match before lower
+    @param is_outbound - entry applies to outbound traffic if non-zero, otherwise applies to inbound traffic
+    @param remote_address_start - start of remote address range to match
+    @param remote_address_stop - end of remote address range to match
+    @param local_address_start - start of local address range to match
+    @param local_address_stop - end of local address range to match
+    @param protocol - protocol type to match [0 means any] otherwise IANA value
+    @param remote_port_start - start of remote port range to match ...
+    @param remote_port_stop - end of remote port range to match [0 to 65535 means ANY, 65535 to 0 means OPAQUE]
+    @param local_port_start - start of local port range to match ...
+    @param local_port_stop - end of remote port range to match [0 to 65535 means ANY, 65535 to 0 means OPAQUE]
+    @param policy - action to perform on match
+    @param sa_id - SAD instance id (control plane allocated)
+*/
+typedef ipsec_spd_entry
+{
+  u32 spd_id;
+  i32 priority;
+  bool is_outbound;
+
+  u32 sa_id;
+  vl_api_ipsec_spd_action_t policy;
+  /* Which protocol?? */
+  u8 protocol;
+
+  // Selector
+  vl_api_address_t remote_address_start;
+  vl_api_address_t remote_address_stop;
+  vl_api_address_t local_address_start;
+  vl_api_address_t local_address_stop;
+
+  u16 remote_port_start;
+  u16 remote_port_stop;
+  u16 local_port_start;
+  u16 local_port_stop;
+};
+
+/** \brief IPsec: Security Policy Database entry v2
+
+    See RFC 4301, 4.4.1.1 on how to match packet to selectors
+
+    @param spd_id - SPD instance id (control plane allocated)
+    @param priority - priority of SPD entry (non-unique value).  Used to order SPD matching - higher priorities match before lower
+    @param is_outbound - entry applies to outbound traffic if non-zero, otherwise applies to inbound traffic
+    @param remote_address_start - start of remote address range to match
+    @param remote_address_stop - end of remote address range to match
+    @param local_address_start - start of local address range to match
+    @param local_address_stop - end of local address range to match
+    @param protocol - protocol type to match [255 means any] otherwise IANA value
+    @param remote_port_start - start of remote port range to match ...
+    @param remote_port_stop - end of remote port range to match [0 to 65535 means ANY, 65535 to 0 means OPAQUE]
+    @param local_port_start - start of local port range to match ...
+    @param local_port_stop - end of remote port range to match [0 to 65535 means ANY, 65535 to 0 means OPAQUE]
+    @param policy - action to perform on match
+    @param sa_id - SAD instance id (control plane allocated)
+*/
+typedef ipsec_spd_entry_v2
+{
+  u32 spd_id;
+  i32 priority;
+  bool is_outbound;
+
+  u32 sa_id;
+  vl_api_ipsec_spd_action_t policy;
+  u8 protocol;
+
+  // Selector
+  vl_api_address_t remote_address_start;
+  vl_api_address_t remote_address_stop;
+  vl_api_address_t local_address_start;
+  vl_api_address_t local_address_stop;
+
+  u16 remote_port_start;
+  u16 remote_port_stop;
+  u16 local_port_start;
+  u16 local_port_stop;
+};
+
+
 /** \brief IPsec: Security Association Database entry
     @param client_index - opaque cookie to identify the sender
     @param context - sender context, to match reply w/ request
@@ -117,6 +213,7 @@
     @param tunnel_flags - Flags controlling the copying of encap/decap value
     @param dscp - Fixed DSCP vaule for tunnel encap
  */
+
 typedef ipsec_sad_entry
 {
   u32 sad_id;