fib: fix crash while adding intf-rx routes

Fix crash while adding intf-rx ip4 and ip6 routes via api due
invalid exporting of interface rx routes as attached.
Also, add missed route path via rx-ip6 cli support.

Type: fix
Signed-off-by: Vladislav Grishenko <themiron@yandex-team.ru>
Change-Id: I15711c8c0787398dd7e3baa4787019bb1f317666
diff --git a/src/vnet/bier/bier_update.c b/src/vnet/bier/bier_update.c
index 4108d09..fdb7c5c 100644
--- a/src/vnet/bier/bier_update.c
+++ b/src/vnet/bier/bier_update.c
@@ -129,7 +129,14 @@
 
 VLIB_CLI_COMMAND (bier_route_command) = {
   .path = "bier route",
-  .short_help = "bier route [add|del] sd <sud-domain> set <set> bsl <bit-string-length> bp <bit-position> via [next-hop-address] [next-hop-interface] [next-hop-table <value>] [weight <value>] [preference <value>] [udp-encap-id <value>] [ip4-lookup-in-table <value>] [ip6-lookup-in-table <value>] [mpls-lookup-in-table <value>] [resolve-via-host] [resolve-via-connected] [rx-ip4 <interface>] [out-labels <value value value>]",
+  .short_help =
+    "bier route [add|del] sd <sud-domain> set <set> bsl <bit-string-length> "
+    "bp <bit-position> via [next-hop-address] [next-hop-interface] "
+    "[next-hop-table <value>] [weight <value>] [preference <value>] "
+    "[udp-encap-id <value>] [ip4-lookup-in-table <value>] "
+    "[ip6-lookup-in-table <value>] [mpls-lookup-in-table <value>] "
+    "[resolve-via-host] [resolve-via-connected] [rx-ip4|rx-ip6 <interface>] "
+    "[out-labels <value value value>]",
   .function = vnet_bier_route_cmd,
 };
 
diff --git a/src/vnet/fib/fib_types.c b/src/vnet/fib/fib_types.c
index 5c5fd0b..c4472c7 100644
--- a/src/vnet/fib/fib_types.c
+++ b/src/vnet/fib/fib_types.c
@@ -708,6 +708,13 @@
             rpath->frp_proto = DPO_PROTO_IP4;
             rpath->frp_flags = FIB_ROUTE_PATH_INTF_RX;
         }
+        else if (unformat (input, "rx-ip6 %U",
+                           unformat_vnet_sw_interface, vnm,
+                           &rpath->frp_sw_if_index))
+        {
+            rpath->frp_proto = DPO_PROTO_IP6;
+            rpath->frp_flags = FIB_ROUTE_PATH_INTF_RX;
+        }
       else if (unformat (input, "local"))
 	{
 	  clib_memset (&rpath->frp_addr, 0, sizeof (rpath->frp_addr));
@@ -775,6 +782,7 @@
      * L3 game with these
      */
     if (rpath->frp_flags & (FIB_ROUTE_PATH_DVR |
+                            FIB_ROUTE_PATH_INTF_RX |
                             FIB_ROUTE_PATH_UDP_ENCAP))
     {
         return (0);
diff --git a/src/vnet/fib/fib_types.h b/src/vnet/fib/fib_types.h
index 49a4b39..b9346c7 100644
--- a/src/vnet/fib/fib_types.h
+++ b/src/vnet/fib/fib_types.h
@@ -633,7 +633,7 @@
 /**
  * A help string to list the FIB path options
  */
-#define FIB_ROUTE_PATH_HELP "[next-hop-address] [next-hop-interface] [next-hop-table <value>] [weight <value>] [preference <value>] [udp-encap-id <value>] [ip4-lookup-in-table <value>] [ip6-lookup-in-table <value>] [mpls-lookup-in-table <value>] [resolve-via-host] [resolve-via-connected] [rx-ip4 <interface>] [out-labels <value value value>]"
+#define FIB_ROUTE_PATH_HELP "[next-hop-address] [next-hop-interface] [next-hop-table <value>] [weight <value>] [preference <value>] [udp-encap-id <value>] [ip4-lookup-in-table <value>] [ip6-lookup-in-table <value>] [mpls-lookup-in-table <value>] [resolve-via-host] [resolve-via-connected] [rx-ip4|rx-ip6 <interface>] [out-labels <value value value>]"
 
 /**
  * return code to control pat-hlist walk
diff --git a/src/vnet/ip/lookup.c b/src/vnet/ip/lookup.c
index 80a35fe..f86c8b6 100644
--- a/src/vnet/ip/lookup.c
+++ b/src/vnet/ip/lookup.c
@@ -620,7 +620,7 @@
 		"[next-hop-table <value>] [weight <value>] [preference "
 		"<value>] [udp-encap <value>] [ip4-lookup-in-table <value>] "
 		"[ip6-lookup-in-table <value>] [mpls-lookup-in-table <value>] "
-		"[resolve-via-host] [resolve-via-connected] [rx-ip4 "
+		"[resolve-via-host] [resolve-via-connected] [rx-ip4|rx-ip6 "
 		"<interface>] [out-labels <value value value>]",
   .function = vnet_ip_route_cmd,
   .is_mp_safe = 1,
diff --git a/src/vnet/mpls/mpls.c b/src/vnet/mpls/mpls.c
index 0d01010..a04e1cf 100644
--- a/src/vnet/mpls/mpls.c
+++ b/src/vnet/mpls/mpls.c
@@ -370,7 +370,13 @@
 VLIB_CLI_COMMAND (mpls_local_label_command, static) = {
   .path = "mpls local-label",
   .function = vnet_mpls_local_label,
-  .short_help = "mpls local-label [add|del] <label-value> [eos|non-eos] via [next-hop-address] [next-hop-interface] [next-hop-table <value>] [weight <value>] [preference <value>] [udp-encap-id <value>] [ip4-lookup-in-table <value>] [ip6-lookup-in-table <value>] [mpls-lookup-in-table <value>] [resolve-via-host] [resolve-via-attached] [rx-ip4 <interface>] [out-labels <value value value>]",
+  .short_help =
+    "mpls local-label [add|del] <label-value> [eos|non-eos] via "
+    "[next-hop-address] [next-hop-interface] [next-hop-table <value>] [weight "
+    "<value>] [preference <value>] [udp-encap-id <value>] "
+    "[ip4-lookup-in-table <value>] [ip6-lookup-in-table <value>] "
+    "[mpls-lookup-in-table <value>] [resolve-via-host] [resolve-via-attached] "
+    "[rx-ip4|rx-ip6 <interface>] [out-labels <value value value>]",
 };
 
 clib_error_t *
diff --git a/src/vnet/mpls/mpls_tunnel.c b/src/vnet/mpls/mpls_tunnel.c
index 5f7bf8c..b03a4a5 100644
--- a/src/vnet/mpls/mpls_tunnel.c
+++ b/src/vnet/mpls/mpls_tunnel.c
@@ -932,7 +932,12 @@
 VLIB_CLI_COMMAND (create_mpls_tunnel_command, static) = {
   .path = "mpls tunnel",
   .short_help =
-  "mpls tunnel [multicast] [l2-only] via [next-hop-address] [next-hop-interface] [next-hop-table <value>] [weight <value>] [preference <value>] [udp-encap-id <value>] [ip4-lookup-in-table <value>] [ip6-lookup-in-table <value>] [mpls-lookup-in-table <value>] [resolve-via-host] [resolve-via-connected] [rx-ip4 <interface>] [out-labels <value value value>]",
+    "mpls tunnel [multicast] [l2-only] via [next-hop-address] "
+    "[next-hop-interface] [next-hop-table <value>] [weight <value>] "
+    "[preference <value>] [udp-encap-id <value>] [ip4-lookup-in-table "
+    "<value>] [ip6-lookup-in-table <value>] [mpls-lookup-in-table <value>] "
+    "[resolve-via-host] [resolve-via-connected] [rx-ip4|rx-ip6 <interface>] "
+    "[out-labels <value value value>]",
   .function = vnet_create_mpls_tunnel_command_fn,
 };
 
diff --git a/test/test_ip4.py b/test/test_ip4.py
index a2a8471..926ca77 100644
--- a/test/test_ip4.py
+++ b/test/test_ip4.py
@@ -3295,5 +3295,138 @@
             i.admin_down()
 
 
+class TestIP4InterfaceRx(VppTestCase):
+    """IPv4 Interface Receive"""
+
+    @classmethod
+    def setUpClass(cls):
+        super(TestIP4InterfaceRx, cls).setUpClass()
+
+    @classmethod
+    def tearDownClass(cls):
+        super(TestIP4InterfaceRx, cls).tearDownClass()
+
+    def setUp(self):
+        super(TestIP4InterfaceRx, self).setUp()
+
+        self.create_pg_interfaces(range(3))
+
+        table_id = 0
+
+        for i in self.pg_interfaces:
+            i.admin_up()
+
+            if table_id != 0:
+                table = VppIpTable(self, table_id)
+                table.add_vpp_config()
+
+            i.set_table_ip4(table_id)
+            i.config_ip4()
+            i.resolve_arp()
+            table_id += 1
+
+    def tearDown(self):
+        for i in self.pg_interfaces:
+            i.unconfig_ip4()
+            i.admin_down()
+            i.set_table_ip4(0)
+
+        super(TestIP4InterfaceRx, self).tearDown()
+
+    def test_interface_rx(self):
+        """IPv4 Interface Receive"""
+
+        #
+        # add a route in the default table to receive ...
+        #
+        route_to_dst = VppIpRoute(
+            self,
+            "1.1.1.0",
+            24,
+            [
+                VppRoutePath(
+                    "0.0.0.0",
+                    self.pg1.sw_if_index,
+                    type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
+                )
+            ],
+        )
+        route_to_dst.add_vpp_config()
+
+        #
+        # packets to these destination are dropped, since they'll
+        # hit the respective default routes in table 1
+        #
+        p_dst = (
+            Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
+            / IP(src="5.5.5.5", dst="1.1.1.1")
+            / TCP(sport=1234, dport=1234)
+            / Raw(b"\xa5" * 100)
+        )
+        pkts_dst = p_dst * 10
+
+        self.send_and_assert_no_replies(self.pg0, pkts_dst, "IP in table 1")
+
+        #
+        # add a route in the dst table to forward via pg1
+        #
+        route_in_dst = VppIpRoute(
+            self,
+            "1.1.1.1",
+            32,
+            [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)],
+            table_id=1,
+        )
+        route_in_dst.add_vpp_config()
+
+        self.send_and_expect(self.pg0, pkts_dst, self.pg1)
+
+        #
+        # add a route in the default table to receive ...
+        #
+        route_to_dst = VppIpRoute(
+            self,
+            "1.1.1.0",
+            24,
+            [
+                VppRoutePath(
+                    "0.0.0.0",
+                    self.pg2.sw_if_index,
+                    type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
+                )
+            ],
+            table_id=1,
+        )
+        route_to_dst.add_vpp_config()
+
+        #
+        # packets to these destination are dropped, since they'll
+        # hit the respective default routes in table 2
+        #
+        p_dst = (
+            Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
+            / IP(src="6.6.6.6", dst="1.1.1.2")
+            / TCP(sport=1234, dport=1234)
+            / Raw(b"\xa5" * 100)
+        )
+        pkts_dst = p_dst * 10
+
+        self.send_and_assert_no_replies(self.pg0, pkts_dst, "IP in table 2")
+
+        #
+        # add a route in the table 2 to forward via pg2
+        #
+        route_in_dst = VppIpRoute(
+            self,
+            "1.1.1.2",
+            32,
+            [VppRoutePath(self.pg2.remote_ip4, self.pg2.sw_if_index)],
+            table_id=2,
+        )
+        route_in_dst.add_vpp_config()
+
+        self.send_and_expect(self.pg0, pkts_dst, self.pg2)
+
+
 if __name__ == "__main__":
     unittest.main(testRunner=VppTestRunner)
diff --git a/test/test_ip6.py b/test/test_ip6.py
index 1e846a6..87509f3 100644
--- a/test/test_ip6.py
+++ b/test/test_ip6.py
@@ -4087,5 +4087,138 @@
         self.assertEqual(str(punts[2].punt.nh), "::")
 
 
+class TestIP6InterfaceRx(VppTestCase):
+    """IPv6 Interface Receive"""
+
+    @classmethod
+    def setUpClass(cls):
+        super(TestIP6InterfaceRx, cls).setUpClass()
+
+    @classmethod
+    def tearDownClass(cls):
+        super(TestIP6InterfaceRx, cls).tearDownClass()
+
+    def setUp(self):
+        super(TestIP6InterfaceRx, self).setUp()
+
+        self.create_pg_interfaces(range(3))
+
+        table_id = 0
+
+        for i in self.pg_interfaces:
+            i.admin_up()
+
+            if table_id != 0:
+                table = VppIpTable(self, table_id, is_ip6=1)
+                table.add_vpp_config()
+
+            i.set_table_ip6(table_id)
+            i.config_ip6()
+            i.resolve_ndp()
+            table_id += 1
+
+    def tearDown(self):
+        for i in self.pg_interfaces:
+            i.unconfig_ip6()
+            i.admin_down()
+            i.set_table_ip6(0)
+
+        super(TestIP6InterfaceRx, self).tearDown()
+
+    def test_interface_rx(self):
+        """IPv6 Interface Receive"""
+
+        #
+        # add a route in the default table to receive ...
+        #
+        route_to_dst = VppIpRoute(
+            self,
+            "1::",
+            122,
+            [
+                VppRoutePath(
+                    "::",
+                    self.pg1.sw_if_index,
+                    type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
+                )
+            ],
+        )
+        route_to_dst.add_vpp_config()
+
+        #
+        # packets to these destination are dropped, since they'll
+        # hit the respective default routes in table 1
+        #
+        p_dst = (
+            Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
+            / IPv6(src="5::5", dst="1::1")
+            / inet6.TCP(sport=1234, dport=1234)
+            / Raw(b"\xa5" * 100)
+        )
+        pkts_dst = p_dst * 10
+
+        self.send_and_assert_no_replies(self.pg0, pkts_dst, "IP in table 1")
+
+        #
+        # add a route in the dst table to forward via pg1
+        #
+        route_in_dst = VppIpRoute(
+            self,
+            "1::1",
+            128,
+            [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index)],
+            table_id=1,
+        )
+        route_in_dst.add_vpp_config()
+
+        self.send_and_expect(self.pg0, pkts_dst, self.pg1)
+
+        #
+        # add a route in the default table to receive ...
+        #
+        route_to_dst = VppIpRoute(
+            self,
+            "1::",
+            122,
+            [
+                VppRoutePath(
+                    "::",
+                    self.pg2.sw_if_index,
+                    type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
+                )
+            ],
+            table_id=1,
+        )
+        route_to_dst.add_vpp_config()
+
+        #
+        # packets to these destination are dropped, since they'll
+        # hit the respective default routes in table 2
+        #
+        p_dst = (
+            Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
+            / IPv6(src="6::6", dst="1::2")
+            / inet6.TCP(sport=1234, dport=1234)
+            / Raw(b"\xa5" * 100)
+        )
+        pkts_dst = p_dst * 10
+
+        self.send_and_assert_no_replies(self.pg0, pkts_dst, "IP in table 2")
+
+        #
+        # add a route in the table 2 to forward via pg2
+        #
+        route_in_dst = VppIpRoute(
+            self,
+            "1::2",
+            128,
+            [VppRoutePath(self.pg2.remote_ip6, self.pg2.sw_if_index)],
+            table_id=2,
+        )
+        route_in_dst.add_vpp_config()
+
+        self.send_and_expect(self.pg0, pkts_dst, self.pg2)
+
+
 if __name__ == "__main__":
     unittest.main(testRunner=VppTestRunner)