gbp: An Endpoint can change sclass 75/20575/2
authorNeale Ranns <nranns@cisco.com>
Wed, 10 Jul 2019 08:14:58 +0000 (01:14 -0700)
committerFlorin Coras <florin.coras@gmail.com>
Thu, 11 Jul 2019 16:08:08 +0000 (16:08 +0000)
Type: feature

Change-Id: I9d3a73a6a6048fa0189f7fa6306a638279977fcd
Signed-off-by: Neale Ranns <nranns@cisco.com>
src/plugins/gbp/gbp_endpoint.c
src/plugins/gbp/gbp_endpoint_group.c
src/plugins/gbp/gbp_learn_node.c
test/test_gbp.py

index 836930a..611e344 100644 (file)
@@ -498,18 +498,12 @@ gbp_endpoint_loc_update (const gbp_endpoint_t * ge,
 
   gbp_endpoint_n_learned (is_learnt - was_learnt);
 
-  if (INDEX_INVALID == gel->gel_epg)
-    {
-      gel->gel_epg = ggi;
-      if (INDEX_INVALID != gel->gel_epg)
-       {
-         gbp_endpoint_group_lock (gel->gel_epg);
-       }
-    }
-  else
-    {
-      ASSERT (gel->gel_epg == ggi);
-    }
+  /*
+   * update the EPG
+   */
+  gbp_endpoint_group_lock (ggi);
+  gbp_endpoint_group_unlock (gel->gel_epg);
+  gel->gel_epg = ggi;
 
   if (gel->gel_flags & GBP_ENDPOINT_FLAG_REMOTE)
     {
index 19c05f9..92bad37 100644 (file)
@@ -52,11 +52,14 @@ gbp_endpoint_group_get (index_t i)
 }
 
 void
-gbp_endpoint_group_lock (index_t i)
+gbp_endpoint_group_lock (index_t ggi)
 {
   gbp_endpoint_group_t *gg;
 
-  gg = gbp_endpoint_group_get (i);
+  if (INDEX_INVALID == ggi)
+    return;
+
+  gg = gbp_endpoint_group_get (ggi);
   gg->gg_locks++;
 }
 
index 113969a..a6c5497 100644 (file)
@@ -179,6 +179,28 @@ gbp_learn_get_outer (const ethernet_header_t * eh0,
   *outer_dst = ip0->dst_address;
 }
 
+always_inline int
+gbp_endpoint_update_required (const gbp_endpoint_t * ge0,
+                             u32 rx_sw_if_index, sclass_t sclass)
+{
+  /* Conditions for [re]learning this EP */
+
+  /* 1. it doesn't have a dataplane source */
+  if (!gbp_endpoint_is_learnt (ge0))
+    return (!0);
+
+  /* 2. has the input interface changed */
+  if (gbp_itf_get_sw_if_index (ge0->ge_fwd.gef_itf) != rx_sw_if_index)
+    return (!0);
+
+  /* 3. has the sclass changed */
+  if (sclass != ge0->ge_fwd.gef_sclass)
+    return (!0);
+
+  /* otherwise it's unchanged */
+  return (0);
+}
+
 VLIB_NODE_FN (gbp_learn_l2_node) (vlib_main_t * vm,
                                  vlib_node_runtime_t * node,
                                  vlib_frame_t * frame)
@@ -246,7 +268,7 @@ VLIB_NODE_FN (gbp_learn_l2_node) (vlib_main_t * vm,
           * check for new EP or a moved EP
           */
          if (NULL == ge0 ||
-             gbp_itf_get_sw_if_index (ge0->ge_fwd.gef_itf) != sw_if_index0)
+             gbp_endpoint_update_required (ge0, sw_if_index0, sclass0))
            {
              /*
               * use the last 4 bytes of the mac address as the hash for the EP
@@ -543,7 +565,8 @@ gbp_learn_l3 (vlib_main_t * vm,
 
              ge0 = gbp_endpoint_find_ip6 (&ip6_0->src_address, fib_index0);
 
-             if ((NULL == ge0) || !gbp_endpoint_is_learnt (ge0))
+             if ((NULL == ge0) ||
+                 gbp_endpoint_update_required (ge0, sw_if_index0, sclass0))
                {
                  t0 = throttle_check (&glm->gl_l3_throttle,
                                       thread_index,
@@ -576,7 +599,8 @@ gbp_learn_l3 (vlib_main_t * vm,
              gbp_learn_get_outer (eth0, &outer_src, &outer_dst);
              ge0 = gbp_endpoint_find_ip4 (&ip4_0->src_address, fib_index0);
 
-             if ((NULL == ge0) || !gbp_endpoint_is_learnt (ge0))
+             if ((NULL == ge0) ||
+                 gbp_endpoint_update_required (ge0, sw_if_index0, sclass0))
                {
                  t0 = throttle_check (&glm->gl_l3_throttle, thread_index,
                                       ip4_0->src_address.as_u32, seed);
index 9cf1817..f6bded6 100644 (file)
@@ -35,7 +35,8 @@ except NameError:
 NUM_PKTS = 67
 
 
-def find_gbp_endpoint(test, sw_if_index=None, ip=None, mac=None, tep=None):
+def find_gbp_endpoint(test, sw_if_index=None, ip=None, mac=None,
+                      tep=None, sclass=None):
     if ip:
         vip = VppIpAddress(ip)
     if mac:
@@ -52,6 +53,9 @@ def find_gbp_endpoint(test, sw_if_index=None, ip=None, mac=None, tep=None):
         if sw_if_index:
             if ep.endpoint.sw_if_index != sw_if_index:
                 continue
+        if sclass:
+            if ep.endpoint.sclass != sclass:
+                continue
         if ip:
             for eip in ep.endpoint.ips:
                 if vip == eip:
@@ -2089,6 +2093,7 @@ class TestGBP(VppTestCase):
             self.assertTrue(find_gbp_endpoint(
                 self,
                 vx_tun_l2_1.sw_if_index,
+                sclass=113,
                 mac=l['mac'],
                 tep=[self.pg2.local_ip4,
                      self.pg2.remote_hosts[2].ip4]))
@@ -2117,6 +2122,65 @@ class TestGBP(VppTestCase):
                 self.assertFalse(rx[VXLAN].gpflags.D)
                 self.assertEqual(rx[IPv6].dst, l['ip6'])
 
+        #
+        # EP changes sclass
+        #
+        for l in learnt:
+            # a packet with an sclass from a known EPG
+            p = (Ether(src=self.pg2.remote_mac,
+                       dst=self.pg2.local_mac) /
+                 IP(src=self.pg2.remote_hosts[2].ip4,
+                    dst=self.pg2.local_ip4) /
+                 UDP(sport=1234, dport=48879) /
+                 VXLAN(vni=99, gpid=112, flags=0x88) /
+                 Ether(src=l['mac'], dst=ep.mac) /
+                 IPv6(src=l['ip6'], dst=ep.ip6.address) /
+                 UDP(sport=1234, dport=1234) /
+                 Raw('\xa5' * 100))
+
+            rx = self.send_and_expect(self.pg2, p * 1, self.pg0)
+            rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
+
+            self.assertTrue(find_gbp_endpoint(
+                self,
+                vx_tun_l2_1.sw_if_index,
+                mac=l['mac'],
+                sclass=112,
+                tep=[self.pg2.local_ip4,
+                     self.pg2.remote_hosts[2].ip4]))
+
+        #
+        # check reachability and contract intra-epg
+        #
+        allow_intra_class = self.statistics.get_err_counter(
+            '/err/gbp-policy-mac/allow-intra-sclass')
+
+        for l in learnt:
+            p = (Ether(src=ep.mac, dst=l['mac']) /
+                 IPv6(dst=l['ip6'], src=ep.ip6.address) /
+                 UDP(sport=1234, dport=1234) /
+                 Raw('\xa5' * 100))
+
+            rxs = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg2)
+
+            for rx in rxs:
+                self.assertEqual(rx[IP].src, self.pg2.local_ip4)
+                self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[2].ip4)
+                self.assertEqual(rx[UDP].dport, 48879)
+                self.assertEqual(rx[VXLAN].gpid, 112)
+                self.assertEqual(rx[VXLAN].vni, 99)
+                self.assertTrue(rx[VXLAN].flags.G)
+                self.assertTrue(rx[VXLAN].flags.Instance)
+                self.assertTrue(rx[VXLAN].gpflags.A)
+                self.assertFalse(rx[VXLAN].gpflags.D)
+                self.assertEqual(rx[IPv6].dst, l['ip6'])
+
+            allow_intra_class += NUM_PKTS
+
+        self.assert_error_counter_equal(
+            '/err/gbp-policy-mac/allow-intra-sclass',
+            allow_intra_class)
+
         #
         # clean up
         #