dhcp ip: DSCP settings for transmitted DHCP packets 48/20748/6
authorNeale Ranns <nranns@cisco.com>
Fri, 19 Jul 2019 14:01:02 +0000 (14:01 +0000)
committerDamjan Marion <dmarion@me.com>
Fri, 26 Jul 2019 13:27:14 +0000 (13:27 +0000)
Type: feature

- Define the ip_dscp_t and use in the IP headers
- Add DSCP setting to the DHCP client for use with packet TX

Change-Id: If220dde0017ea78793747d65f53e11daf23a28fa
Signed-off-by: Neale Ranns <nranns@cisco.com>
22 files changed:
extras/vom/vom/dhcp_client.cpp
extras/vom/vom/dhcp_client.hpp
extras/vom/vom/dhcp_client_cmds.cpp
extras/vom/vom/dhcp_client_cmds.hpp
extras/vom/vom/prefix.cpp
extras/vom/vom/prefix.hpp
extras/vom/vom/route_api_types.cpp
extras/vom/vom/route_api_types.hpp
src/vnet/dhcp/client.c
src/vnet/dhcp/client.h
src/vnet/dhcp/dhcp.api
src/vnet/dhcp/dhcp_api.c
src/vnet/ip/ip.c
src/vnet/ip/ip4_packet.h
src/vnet/ip/ip6_packet.h
src/vnet/ip/ip_packet.h
src/vnet/ip/ip_types.api
src/vnet/ip/ip_types_api.c
src/vnet/ip/ip_types_api.h
src/vnet/mpls/packet.h
test/test_dhcp.py
test/vpp_papi_provider.py

index fcadfa6..e3a5b9d 100644 (file)
@@ -15,6 +15,7 @@
 
 #include "vom/dhcp_client.hpp"
 #include "vom/dhcp_client_cmds.hpp"
+#include "vom/route_api_types.hpp"
 #include "vom/singular_db_funcs.hpp"
 
 namespace VOM {
@@ -47,11 +48,13 @@ dhcp_client::event_handler dhcp_client::m_evh;
 dhcp_client::dhcp_client(const interface& itf,
                          const std::string& hostname,
                          bool set_broadcast_flag,
+                         const ip_dscp_t& dscp,
                          event_listener* ev)
   : m_itf(itf.singular())
   , m_hostname(hostname)
   , m_client_id(l2_address_t::ZERO)
   , m_set_broadcast_flag(set_broadcast_flag)
+  , m_dscp(dscp)
   , m_binding(0)
   , m_evl(ev)
   , m_event_cmd(get_event_cmd())
@@ -62,11 +65,13 @@ dhcp_client::dhcp_client(const interface& itf,
                          const std::string& hostname,
                          const l2_address_t& client_id,
                          bool set_broadcast_flag,
+                         const ip_dscp_t& dscp,
                          event_listener* ev)
   : m_itf(itf.singular())
   , m_hostname(hostname)
   , m_client_id(client_id)
   , m_set_broadcast_flag(set_broadcast_flag)
+  , m_dscp(dscp)
   , m_binding(0)
   , m_evl(ev)
   , m_event_cmd(get_event_cmd())
@@ -78,6 +83,7 @@ dhcp_client::dhcp_client(const dhcp_client& o)
   , m_hostname(o.m_hostname)
   , m_client_id(o.m_client_id)
   , m_set_broadcast_flag(o.m_set_broadcast_flag)
+  , m_dscp(o.m_dscp)
   , m_binding(0)
   , m_evl(o.m_evl)
   , m_event_cmd(o.m_event_cmd)
@@ -96,7 +102,7 @@ bool
 dhcp_client::operator==(const dhcp_client& l) const
 {
   return ((key() == l.key()) && (m_hostname == l.m_hostname) &&
-          (m_client_id == l.m_client_id));
+          (m_client_id == l.m_client_id && m_dscp == l.m_dscp));
 }
 
 const dhcp_client::key_t&
@@ -125,8 +131,8 @@ void
 dhcp_client::replay()
 {
   if (m_binding) {
-    HW::enqueue(new dhcp_client_cmds::bind_cmd(m_binding, m_itf->handle(),
-                                               m_hostname, m_client_id));
+    HW::enqueue(new dhcp_client_cmds::bind_cmd(
+      m_binding, m_itf->handle(), m_hostname, m_client_id, false, m_dscp));
   }
 }
 
@@ -135,7 +141,8 @@ dhcp_client::to_string() const
 {
   std::ostringstream s;
   s << "DHCP-client: " << m_itf->to_string() << " hostname:" << m_hostname
-    << " client_id:[" << m_client_id << "] " << m_binding.to_string();
+    << " client_id:[" << m_client_id << "] "
+    << "dscp:" << m_dscp.to_string() << " " << m_binding.to_string();
   if (m_lease)
     s << " " << m_lease->to_string();
   else
@@ -151,8 +158,8 @@ dhcp_client::update(const dhcp_client& desired)
    * the desired state is always that the interface should be created
    */
   if (!m_binding) {
-    HW::enqueue(new dhcp_client_cmds::bind_cmd(m_binding, m_itf->handle(),
-                                               m_hostname, m_client_id));
+    HW::enqueue(new dhcp_client_cmds::bind_cmd(
+      m_binding, m_itf->handle(), m_hostname, m_client_id, false, m_dscp));
   }
 
   if (desired.m_lease)
@@ -276,7 +283,8 @@ dhcp_client::event_handler::handle_populate(const client_db::key_t& key)
     std::string hostname =
       reinterpret_cast<const char*>(payload.lease.hostname);
     l2_address_t l2(payload.client.id + 1);
-    dhcp_client dc(*itf, hostname, l2, payload.client.set_broadcast_flag);
+    dhcp_client dc(*itf, hostname, l2, payload.client.set_broadcast_flag,
+                   from_api(payload.client.dscp));
     dc.lease(std::make_shared<dhcp_client::lease_t>(
       s, itf, from_bytes(0, payload.lease.router_address), pfx, hostname,
       mac_address_t(payload.lease.host_mac)));
index 17c626e..8e8669a 100644 (file)
@@ -112,6 +112,7 @@ public:
   dhcp_client(const interface& itf,
               const std::string& hostname,
               bool set_broadcast_flag = true,
+              const ip_dscp_t& dscp = ip_dscp_t::DSCP_CS0,
               event_listener* ev = nullptr);
 
   /**
@@ -121,6 +122,7 @@ public:
               const std::string& hostname,
               const l2_address_t& client_id,
               bool set_broadcast_flag = true,
+              const ip_dscp_t& dscp = ip_dscp_t::DSCP_CS0,
               event_listener* ev = nullptr);
 
   /**
@@ -258,6 +260,11 @@ private:
    */
   const bool m_set_broadcast_flag;
 
+  /**
+   * DSCP setting for generated IP packets
+   */
+  const ip_dscp_t m_dscp;
+
   /**
    * HW configuration for the binding. The bool representing the
    * do/don't bind.
index 9b632fe..c1d4d49 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include "vom/dhcp_client_cmds.hpp"
+#include "vom/route_api_types.hpp"
 
 DEFINE_VAPI_MSG_IDS_DHCP_API_JSON;
 
@@ -24,12 +25,14 @@ bind_cmd::bind_cmd(HW::item<bool>& item,
                    const handle_t& itf,
                    const std::string& hostname,
                    const l2_address_t& client_id,
-                   bool set_broadcast_flag)
+                   bool set_broadcast_flag,
+                   const ip_dscp_t& dscp)
   : rpc_cmd(item)
   , m_itf(itf)
   , m_hostname(hostname)
   , m_client_id(client_id)
   , m_set_broadcast_flag(set_broadcast_flag)
+  , m_dscp(dscp)
 {
 }
 
@@ -50,6 +53,7 @@ bind_cmd::issue(connection& con)
   payload.client.pid = getpid();
   payload.client.want_dhcp_event = 1;
   payload.client.set_broadcast_flag = m_set_broadcast_flag;
+  payload.client.dscp = to_api(m_dscp);
 
   memset(payload.client.hostname, 0, sizeof(payload.client.hostname));
   memcpy(payload.client.hostname, m_hostname.c_str(),
@@ -71,7 +75,9 @@ bind_cmd::to_string() const
 {
   std::ostringstream s;
   s << "Dhcp-client-bind: " << m_hw_item.to_string()
-    << " itf:" << m_itf.to_string() << " hostname:" << m_hostname;
+    << " itf:" << m_itf.to_string() << " hostname:" << m_hostname
+    << " client_id:[" << m_client_id << "] "
+    << "dscp:" << m_dscp.to_string();
 
   return (s.str());
 }
index 89fe7ee..10d4026 100644 (file)
@@ -39,7 +39,8 @@ public:
            const handle_t& itf,
            const std::string& hostname,
            const l2_address_t& client_id,
-           bool set_braodcast_flag = false);
+           bool set_braodcast_flag,
+           const ip_dscp_t& dscp);
 
   /**
    * Issue the command to VPP/HW
@@ -75,6 +76,11 @@ private:
    * Flag to control the setting the of DHCP discover's broadcast flag
    */
   const bool m_set_broadcast_flag;
+
+  /**
+   * DSCP bits
+   */
+  const ip_dscp_t& m_dscp;
 };
 
 /**
index a630599..45cb6df 100644 (file)
@@ -96,6 +96,37 @@ nh_proto_t::from_address(const boost::asio::ip::address& addr)
   return IPV4;
 }
 
+const ip_dscp_t ip_dscp_t::DSCP_CS0(0, "CS0");
+const ip_dscp_t ip_dscp_t::DSCP_CS1(8, "CS1");
+const ip_dscp_t ip_dscp_t::DSCP_CS2(16, "CS2");
+const ip_dscp_t ip_dscp_t::DSCP_CS3(24, "CS3");
+const ip_dscp_t ip_dscp_t::DSCP_CS4(32, "CS4");
+const ip_dscp_t ip_dscp_t::DSCP_CS5(40, "CS5");
+const ip_dscp_t ip_dscp_t::DSCP_CS6(48, "CS6");
+const ip_dscp_t ip_dscp_t::DSCP_CS7(50, "CS7");
+const ip_dscp_t ip_dscp_t::DSCP_AF11(10, "AF11");
+const ip_dscp_t ip_dscp_t::DSCP_AF12(12, "AF12");
+const ip_dscp_t ip_dscp_t::DSCP_AF13(14, "AF13");
+const ip_dscp_t ip_dscp_t::DSCP_AF21(18, "AF21");
+const ip_dscp_t ip_dscp_t::DSCP_AF22(20, "AF22");
+const ip_dscp_t ip_dscp_t::DSCP_AF23(22, "AF23");
+const ip_dscp_t ip_dscp_t::DSCP_AF31(26, "AF31");
+const ip_dscp_t ip_dscp_t::DSCP_AF32(28, "AF32");
+const ip_dscp_t ip_dscp_t::DSCP_AF33(30, "AF33");
+const ip_dscp_t ip_dscp_t::DSCP_AF41(34, "AF41");
+const ip_dscp_t ip_dscp_t::DSCP_AF42(36, "AF42");
+const ip_dscp_t ip_dscp_t::DSCP_AF43(38, "AF43");
+const ip_dscp_t ip_dscp_t::DSCP_EF(46, "EF");
+
+ip_dscp_t::ip_dscp_t(int v, const std::string& s)
+  : enum_base<ip_dscp_t>(v, s)
+{
+}
+ip_dscp_t::ip_dscp_t(int v)
+  : enum_base<ip_dscp_t>(v, std::to_string(v))
+{
+}
+
 /**
  * The all Zeros prefix
  */
index b75dc66..fada1d3 100644 (file)
@@ -75,6 +75,45 @@ private:
  */
 std::ostream& operator<<(std::ostream& os, const l3_proto_t& l3p);
 
+/**
+ * IP DSCP values
+ */
+class ip_dscp_t : public enum_base<ip_dscp_t>
+{
+public:
+  /* unfortunately some of the CSX names are defined in terminos.h
+   * as macros, hence the longer names */
+  const static ip_dscp_t DSCP_CS0;
+  const static ip_dscp_t DSCP_CS1;
+  const static ip_dscp_t DSCP_CS2;
+  const static ip_dscp_t DSCP_CS3;
+  const static ip_dscp_t DSCP_CS4;
+  const static ip_dscp_t DSCP_CS5;
+  const static ip_dscp_t DSCP_CS6;
+  const static ip_dscp_t DSCP_CS7;
+  const static ip_dscp_t DSCP_AF11;
+  const static ip_dscp_t DSCP_AF12;
+  const static ip_dscp_t DSCP_AF13;
+  const static ip_dscp_t DSCP_AF21;
+  const static ip_dscp_t DSCP_AF22;
+  const static ip_dscp_t DSCP_AF23;
+  const static ip_dscp_t DSCP_AF31;
+  const static ip_dscp_t DSCP_AF32;
+  const static ip_dscp_t DSCP_AF33;
+  const static ip_dscp_t DSCP_AF41;
+  const static ip_dscp_t DSCP_AF42;
+  const static ip_dscp_t DSCP_AF43;
+  const static ip_dscp_t DSCP_EF;
+
+  /**
+   * Constructor allows the creation of any DSCP value
+   */
+  ip_dscp_t(int v);
+
+private:
+  ip_dscp_t(int v, const std::string& s);
+};
+
 namespace route {
 /**
  * type def the table-id
index 31acc84..b6ab638 100644 (file)
@@ -123,11 +123,68 @@ from_api(const vapi_type_fib_path& p)
   return (route::path(route::path::special_t::DROP));
 };
 
+vapi_enum_ip_dscp
+to_api(const ip_dscp_t& d)
+{
+  return static_cast<vapi_enum_ip_dscp>((int)d);
+}
+const ip_dscp_t&
+from_api(vapi_enum_ip_dscp d)
+{
+  switch (d) {
+    case IP_API_DSCP_CS0:
+      return ip_dscp_t::DSCP_CS0;
+    case IP_API_DSCP_CS1:
+      return ip_dscp_t::DSCP_CS1;
+    case IP_API_DSCP_CS2:
+      return ip_dscp_t::DSCP_CS2;
+    case IP_API_DSCP_CS3:
+      return ip_dscp_t::DSCP_CS3;
+    case IP_API_DSCP_CS4:
+      return ip_dscp_t::DSCP_CS4;
+    case IP_API_DSCP_CS5:
+      return ip_dscp_t::DSCP_CS5;
+    case IP_API_DSCP_CS6:
+      return ip_dscp_t::DSCP_CS6;
+    case IP_API_DSCP_CS7:
+      return ip_dscp_t::DSCP_CS7;
+    case IP_API_DSCP_EF:
+      return ip_dscp_t::DSCP_EF;
+    case IP_API_DSCP_AF11:
+      return ip_dscp_t::DSCP_AF11;
+    case IP_API_DSCP_AF12:
+      return ip_dscp_t::DSCP_AF12;
+    case IP_API_DSCP_AF13:
+      return ip_dscp_t::DSCP_AF13;
+    case IP_API_DSCP_AF21:
+      return ip_dscp_t::DSCP_AF21;
+    case IP_API_DSCP_AF22:
+      return ip_dscp_t::DSCP_AF22;
+    case IP_API_DSCP_AF23:
+      return ip_dscp_t::DSCP_AF23;
+    case IP_API_DSCP_AF31:
+      return ip_dscp_t::DSCP_AF31;
+    case IP_API_DSCP_AF32:
+      return ip_dscp_t::DSCP_AF32;
+    case IP_API_DSCP_AF33:
+      return ip_dscp_t::DSCP_AF33;
+    case IP_API_DSCP_AF41:
+      return ip_dscp_t::DSCP_AF41;
+    case IP_API_DSCP_AF42:
+      return ip_dscp_t::DSCP_AF42;
+    case IP_API_DSCP_AF43:
+      return ip_dscp_t::DSCP_AF43;
+  }
+
+  return ip_dscp_t::DSCP_CS0;
+}
+
 }; // namespace VOM
-   /*
-    * fd.io coding-style-patch-verification: ON
-    *
-    * Local Variables:
-    * eval: (c-set-style "mozilla")
-    * End:
-    */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
index 25d0902..e741a9d 100644 (file)
@@ -26,6 +26,9 @@ void to_api(const route::path& p, vapi_type_fib_path& o);
 
 route::path from_api(const vapi_type_fib_path& p);
 
+vapi_enum_ip_dscp to_api(const ip_dscp_t& d);
+const ip_dscp_t& from_api(vapi_enum_ip_dscp d);
+
 }; // namespace VOM
 
 /*
index 472de52..aaeda96 100644 (file)
@@ -17,6 +17,7 @@
 #include <vnet/dhcp/client.h>
 #include <vnet/dhcp/dhcp_proxy.h>
 #include <vnet/fib/fib_table.h>
+#include <vnet/qos/qos_types.h>
 
 dhcp_client_main_t dhcp_client_main;
 static u8 *format_dhcp_client_state (u8 * s, va_list * va);
@@ -434,6 +435,19 @@ send_dhcp_pkt (dhcp_client_main_t * dcm, dhcp_client_t * c,
   ip->ttl = 128;
   ip->protocol = IP_PROTOCOL_UDP;
 
+  ip->tos = c->dscp;
+
+  if (ip->tos)
+    {
+      /*
+       * Setup the buffer's QoS settings so any QoS marker on the egress
+       * interface, that might set VLAN CoS bits, based on this DSCP setting
+       */
+      vnet_buffer2 (b)->qos.source = QOS_SOURCE_IP;
+      vnet_buffer2 (b)->qos.bits = ip->tos;
+      b->flags |= VNET_BUFFER_F_QOS_DATA_VALID;
+    }
+
   if (is_broadcast)
     {
       /* src = 0.0.0.0, dst = 255.255.255.255 */
@@ -825,6 +839,9 @@ format_dhcp_client (u8 * s, va_list * va)
              format_vnet_sw_if_index_name, dcm->vnet_main, c->sw_if_index,
              format_dhcp_client_state, c->state);
 
+  if (0 != c->dscp)
+    s = format (s, "dscp %d ", c->dscp);
+
   if (c->leased_address.as_u32)
     {
       s = format (s, "addr %U/%d gw %U",
@@ -942,6 +959,7 @@ dhcp_client_add_del (dhcp_client_add_del_args_t * a)
       c->hostname = a->hostname;
       c->client_identifier = a->client_identifier;
       c->set_broadcast_flag = a->set_broadcast_flag;
+      c->dscp = a->dscp;
       c->ai_ucast = ADJ_INDEX_INVALID;
       c->ai_bcast = adj_nbr_add_or_lock (FIB_PROTOCOL_IP4,
                                         VNET_LINK_IP4,
@@ -1011,7 +1029,7 @@ dhcp_client_config (u32 is_add,
                    u8 * hostname,
                    u8 * client_id,
                    dhcp_event_cb_t event_callback,
-                   u8 set_broadcast_flag, u32 pid)
+                   u8 set_broadcast_flag, ip_dscp_t dscp, u32 pid)
 {
   dhcp_client_add_del_args_t _a, *a = &_a;
   int rv;
@@ -1023,6 +1041,7 @@ dhcp_client_config (u32 is_add,
   a->pid = pid;
   a->event_callback = event_callback;
   a->set_broadcast_flag = set_broadcast_flag;
+  a->dscp = dscp;
   vec_validate (a->hostname, strlen ((char *) hostname) - 1);
   strncpy ((char *) a->hostname, (char *) hostname, vec_len (a->hostname));
   vec_validate (a->client_identifier, strlen ((char *) client_id) - 1);
index a79d6e5..5191fcf 100644 (file)
@@ -89,6 +89,8 @@ typedef struct dhcp_client_t_
   adj_index_t ai_ucast;
   /* the broadcast adjacency on the link */
   adj_index_t ai_bcast;
+  /* IP DSCP to set in sent packets */
+  ip_dscp_t dscp;
 
   dhcp_event_cb_t event_callback;
 } dhcp_client_t;
@@ -121,6 +123,7 @@ typedef struct
   /* Information used for event callback */
   u32 client_index;
   u32 pid;
+  ip_dscp_t dscp;
   dhcp_event_cb_t event_callback;
 } dhcp_client_add_del_args_t;
 
@@ -143,7 +146,8 @@ extern int dhcp_client_config (u32 is_add,
                               u8 * hostname,
                               u8 * client_id,
                               dhcp_event_cb_t event_callback,
-                              u8 set_broadcast_flag, u32 pid);
+                              u8 set_broadcast_flag,
+                              ip_dscp_t dscp, u32 pid);
 
 /**
  * callback function for clients walking the DHCP client configurations
index 033c7a3..6db9033 100644 (file)
@@ -15,6 +15,8 @@
 
 option version = "2.0.1";
 
+import "vnet/ip/ip_types.api";
+
 /** \brief DHCP Proxy config add / del request
     @param client_index - opaque cookie to identify the sender
     @param context - sender context, to match reply w/ request
@@ -70,6 +72,7 @@ autoreply define dhcp_proxy_set_vss
            via dhcp_compl_event API message if non-zero
     @param set_broadcast_flag - in the DHCP Discover to control
                                 how the resulting OFFER is addressed.
+    @param dscp - DSCP value set in IP packets sent by the client
     @param pid - sender's pid
 */
 typeonly define dhcp_client
@@ -79,6 +82,7 @@ typeonly define dhcp_client
   u8 id[64];
   u8 want_dhcp_event;
   u8 set_broadcast_flag;
+  vl_api_ip_dscp_t dscp;
   u32 pid;
 };
 
index 7eb2bf4..7935ad8 100644 (file)
@@ -28,6 +28,7 @@
 #include <vnet/dhcp/dhcp6_ia_na_client_dp.h>
 #include <vnet/dhcp/dhcp6_client_common_dp.h>
 #include <vnet/fib/fib_table.h>
+#include <vnet/ip/ip_types_api.h>
 
 #include <vnet/vnet_msg_enum.h>
 
@@ -263,6 +264,7 @@ dhcp_client_data_encode (vl_api_dhcp_client_t * vclient,
   else
     vclient->want_dhcp_event = 0;
   vclient->set_broadcast_flag = client->set_broadcast_flag;
+  vclient->dscp = ip_dscp_encode (client->dscp);
   vclient->pid = client->pid;
 }
 
@@ -292,14 +294,13 @@ static void vl_api_dhcp_client_config_t_handler
   vlib_main_t *vm = vlib_get_main ();
   vl_api_dhcp_client_config_reply_t *rmp;
   u32 sw_if_index;
+  ip_dscp_t dscp;
   int rv = 0;
 
+  VALIDATE_SW_IF_INDEX (&(mp->client));
+
   sw_if_index = ntohl (mp->client.sw_if_index);
-  if (!vnet_sw_if_index_is_api_valid (sw_if_index))
-    {
-      rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
-      goto bad_sw_if_index;
-    }
+  dscp = ip_dscp_decode (mp->client.dscp);
 
   rv = dhcp_client_config (mp->is_add,
                           mp->client_index,
@@ -310,10 +311,10 @@ static void vl_api_dhcp_client_config_t_handler
                           (mp->client.want_dhcp_event ?
                            dhcp_compl_event_callback :
                            NULL),
-                          mp->client.set_broadcast_flag, mp->client.pid);
+                          mp->client.set_broadcast_flag,
+                          dscp, mp->client.pid);
 
   BAD_SW_IF_INDEX_LABEL;
-
   REPLY_MACRO (VL_API_DHCP_CLIENT_CONFIG_REPLY);
 }
 
index 6e8ac7c..133767b 100644 (file)
@@ -294,6 +294,23 @@ format_ip_address_family (u8 * s, va_list * args)
   return (format (s, "unknown"));
 }
 
+u8 *
+format_ip_dscp (u8 * s, va_list * va)
+{
+  ip_dscp_t dscp = va_arg (*va, u32);  // int promotion of u8
+
+  switch (dscp)
+    {
+#define _(n,v)                                                  \
+    case IP_DSCP_##v:                                           \
+      return (format (s, "%s", #v));
+      foreach_ip_dscp
+#undef _
+    }
+
+  return (format (s, "unknon"));
+}
+
 /*
  * fd.io coding-style-patch-verification: ON
  *
index 2ce6763..c1852fc 100644 (file)
@@ -138,7 +138,7 @@ typedef union
     u8 ip_version_and_header_length;
 
     /* Type of service. */
-    u8 tos;
+    ip_dscp_t tos;
 
     /* Total layer 3 packet length including this header. */
     u16 length;
index c8bc4c8..c1bd2aa 100644 (file)
@@ -383,13 +383,13 @@ typedef struct
   ip6_address_t src_address, dst_address;
 } ip6_header_t;
 
-always_inline u8
+always_inline ip_dscp_t
 ip6_traffic_class (const ip6_header_t * i)
 {
   return (i->ip_version_traffic_class_and_flow_label & 0x0FF00000) >> 20;
 }
 
-static_always_inline u8
+static_always_inline ip_dscp_t
 ip6_traffic_class_network_order (const ip6_header_t * ip6)
 {
   return (clib_net_to_host_u32 (ip6->ip_version_traffic_class_and_flow_label)
@@ -397,7 +397,7 @@ ip6_traffic_class_network_order (const ip6_header_t * ip6)
 }
 
 static_always_inline void
-ip6_set_traffic_class_network_order (ip6_header_t * ip6, u8 dscp)
+ip6_set_traffic_class_network_order (ip6_header_t * ip6, ip_dscp_t dscp)
 {
   u32 tmp =
     clib_net_to_host_u32 (ip6->ip_version_traffic_class_and_flow_label);
index c499097..97b3c96 100644 (file)
@@ -84,6 +84,44 @@ typedef enum
 #undef _
 } ip_multicast_group_t;
 
+
+/**
+ * The set of RFC defined DSCP values.
+ */
+#define foreach_ip_dscp                       \
+  _(0, CS0)                                   \
+  _(8, CS1)                                   \
+  _(10, AF11)                                 \
+  _(12, AF12)                                 \
+  _(14, AF13)                                 \
+  _(16, CS2)                                  \
+  _(18, AF21)                                 \
+  _(20, AF22)                                 \
+  _(22, AF23)                                 \
+  _(24, CS3)                                  \
+  _(26, AF31)                                 \
+  _(28, AF32)                                 \
+  _(30, AF33)                                 \
+  _(32, CS4)                                  \
+  _(34, AF41)                                 \
+  _(36, AF42)                                 \
+  _(38, AF43)                                 \
+  _(40, CS5)                                  \
+  _(46, EF)                                   \
+  _(48, CS6)                                  \
+  _(50, CS7)
+
+typedef enum ip_dscp_t_
+{
+#define _(n,f) IP_DSCP_##f = n,
+  foreach_ip_dscp
+#undef _
+} __clib_packed ip_dscp_t;
+
+STATIC_ASSERT_SIZEOF (ip_dscp_t, 1);
+
+extern u8 *format_ip_dscp (u8 * s, va_list * va);
+
 /* IP checksum support. */
 
 static_always_inline u16
index 8b46a1d..13c6a4a 100644 (file)
@@ -34,8 +34,8 @@ enum ip_ecn : u8 {
 
 /* DSCP code points - RFC 2474
    https://tools.ietf.org/html/rfc2474
+   Values other than these RFC defined values are accepted.
 */
-
 enum ip_dscp : u8 {
   IP_API_DSCP_CS0 =  0,
   IP_API_DSCP_CS1 = 8,
index 0343d20..ca26731 100644 (file)
@@ -95,6 +95,18 @@ ip_proto_encode (ip_protocol_t ipp)
   return (clib_host_to_net_u32 (IP_API_PROTO_TCP));
 }
 
+ip_dscp_t
+ip_dscp_decode (u8 in)
+{
+  return ((ip_dscp_t) in);
+}
+
+u8
+ip_dscp_encode (ip_dscp_t dscp)
+{
+  return (dscp);
+}
+
 void
 ip6_address_encode (const ip6_address_t * in, vl_api_ip6_address_t out)
 {
index 4c79bf1..fc7a416 100644 (file)
@@ -41,6 +41,8 @@ extern int ip_address_family_decode (int _af, ip_address_family_t * out);
 extern int ip_address_family_encode (ip_address_family_t af);
 extern int ip_proto_decode (int _af, ip_protocol_t * out);
 extern int ip_proto_encode (ip_protocol_t af);
+extern ip_dscp_t ip_dscp_decode (u8 _dscp);
+extern u8 ip_dscp_encode (ip_dscp_t dscp);
 
 /**
  * Decode/Encode for struct/union types
index ca6ac40..8573bc3 100644 (file)
@@ -1,6 +1,3 @@
-#ifndef included_vnet_mpls_packet_h
-#define included_vnet_mpls_packet_h
-
 /*
  * MPLS packet format
  *
  * limitations under the License.
  */
 
+#ifndef included_vnet_mpls_packet_h
+#define included_vnet_mpls_packet_h
+
+#include <vnet/ip/ip_packet.h>
+
 /**
  * A label value only, i.e. 20bits.
  */
@@ -55,7 +57,7 @@ typedef enum mpls_eos_bit_t_
 /**
  * When in uniform mode convert an IPv[46] DSCP value to an MPLS EXP value
  */
-static inline u8 ip_dscp_to_mpls_exp (u8 tos)
+static inline u8 ip_dscp_to_mpls_exp (ip_dscp_t tos)
 {
     return (tos >> 5);
 }
index fce41a9..16b0f47 100644 (file)
@@ -9,7 +9,7 @@ from vpp_neighbor import VppNeighbor
 from vpp_ip_route import find_route, VppIpTable
 from util import mk_ll_addr
 import scapy.compat
-from scapy.layers.l2 import Ether, getmacbyip, ARP
+from scapy.layers.l2 import Ether, getmacbyip, ARP, Dot1Q
 from scapy.layers.inet import IP, UDP, ICMP
 from scapy.layers.inet6 import IPv6, in6_getnsmac
 from scapy.utils6 import in6_mactoifaceid
@@ -20,7 +20,10 @@ from scapy.layers.dhcp6 import DHCP6, DHCP6_Solicit, DHCP6_RelayForward, \
 from socket import AF_INET, AF_INET6
 from scapy.utils import inet_pton, inet_ntop
 from scapy.utils6 import in6_ptop
-from vpp_papi import mac_pton
+from vpp_papi import mac_pton, VppEnum
+from vpp_sub_interface import VppDot1QSubint
+from vpp_qos import VppQosEgressMap, VppQosMark
+
 
 DHCP4_CLIENT_PORT = 68
 DHCP4_SERVER_PORT = 67
@@ -210,7 +213,7 @@ class TestDHCP(VppTestCase):
         data = self.validate_relay_options(pkt, intf, intf.local_ip4,
                                            vpn_id, fib_id, oui)
 
-    def verify_orig_dhcp_pkt(self, pkt, intf, l2_bc=True):
+    def verify_orig_dhcp_pkt(self, pkt, intf, dscp, l2_bc=True):
         ether = pkt[Ether]
         if l2_bc:
             self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
@@ -226,14 +229,15 @@ class TestDHCP(VppTestCase):
         else:
             self.assertEqual(ip.dst, intf.remote_ip4)
             self.assertEqual(ip.src, intf.local_ip4)
+        self.assertEqual(ip.tos, dscp)
 
         udp = pkt[UDP]
         self.assertEqual(udp.dport, DHCP4_SERVER_PORT)
         self.assertEqual(udp.sport, DHCP4_CLIENT_PORT)
 
     def verify_orig_dhcp_discover(self, pkt, intf, hostname, client_id=None,
-                                  broadcast=True):
-        self.verify_orig_dhcp_pkt(pkt, intf)
+                                  broadcast=True, dscp=0):
+        self.verify_orig_dhcp_pkt(pkt, intf, dscp)
 
         self.verify_dhcp_msg_type(pkt, "discover")
         self.verify_dhcp_has_option(pkt, "hostname", hostname)
@@ -249,8 +253,9 @@ class TestDHCP(VppTestCase):
 
     def verify_orig_dhcp_request(self, pkt, intf, hostname, ip,
                                  broadcast=True,
-                                 l2_bc=True):
-        self.verify_orig_dhcp_pkt(pkt, intf, l2_bc=l2_bc)
+                                 l2_bc=True,
+                                 dscp=0):
+        self.verify_orig_dhcp_pkt(pkt, intf, dscp, l2_bc=l2_bc)
 
         self.verify_dhcp_msg_type(pkt, "request")
         self.verify_dhcp_has_option(pkt, "hostname", hostname)
@@ -1229,6 +1234,7 @@ class TestDHCP(VppTestCase):
     def test_dhcp_client(self):
         """ DHCP Client"""
 
+        vdscp = VppEnum.vl_api_ip_dscp_t
         hostname = 'universal-dp'
 
         self.pg_enable_capture(self.pg_interfaces)
@@ -1316,17 +1322,20 @@ class TestDHCP(VppTestCase):
 
         #
         # Start the procedure again. this time have VPP send the client-ID
+        # and set the DSCP value
         #
         self.pg3.admin_down()
         self.sleep(1)
         self.pg3.admin_up()
         self.vapi.dhcp_client_config(self.pg3.sw_if_index, hostname,
-                                     client_id=self.pg3.local_mac)
+                                     client_id=self.pg3.local_mac,
+                                     dscp=vdscp.IP_API_DSCP_EF)
 
         rx = self.pg3.get_capture(1)
 
         self.verify_orig_dhcp_discover(rx[0], self.pg3, hostname,
-                                       self.pg3.local_mac)
+                                       self.pg3.local_mac,
+                                       dscp=vdscp.IP_API_DSCP_EF)
 
         # TODO: VPP DHCP client should not accept DHCP OFFER message with
         # the XID (Transaction ID) not matching the XID of the most recent
@@ -1339,7 +1348,8 @@ class TestDHCP(VppTestCase):
 
         rx = self.pg3.get_capture(1)
         self.verify_orig_dhcp_request(rx[0], self.pg3, hostname,
-                                      self.pg3.local_ip4)
+                                      self.pg3.local_ip4,
+                                      dscp=vdscp.IP_API_DSCP_EF)
 
         #
         # unicast the ack to the offered address
@@ -1610,6 +1620,48 @@ class TestDHCP(VppTestCase):
         #
         self.vapi.dhcp_client_config(self.pg3.sw_if_index, hostname, is_add=0)
 
+    def test_dhcp_client_vlan(self):
+        """ DHCP Client w/ VLAN"""
+
+        vdscp = VppEnum.vl_api_ip_dscp_t
+        vqos = VppEnum.vl_api_qos_source_t
+        hostname = 'universal-dp'
+
+        self.pg_enable_capture(self.pg_interfaces)
+
+        vlan_100 = VppDot1QSubint(self, self.pg3, 100)
+        vlan_100.admin_up()
+
+        output = [scapy.compat.chb(4)] * 256
+        os = b''.join(output)
+        rows = [{'outputs': os},
+                {'outputs': os},
+                {'outputs': os},
+                {'outputs': os}]
+
+        qem1 = VppQosEgressMap(self, 1, rows).add_vpp_config()
+        qm1 = VppQosMark(self, vlan_100, qem1,
+                         vqos.QOS_API_SOURCE_VLAN).add_vpp_config()
+
+        #
+        # Configure DHCP client on PG3 and capture the discover sent
+        #
+        self.vapi.dhcp_client_config(vlan_100.sw_if_index,
+                                     hostname,
+                                     dscp=vdscp.IP_API_DSCP_EF)
+
+        rx = self.pg3.get_capture(1)
+
+        self.assertEqual(rx[0][Dot1Q].vlan, 100)
+        self.assertEqual(rx[0][Dot1Q].prio, 4)
+
+        self.verify_orig_dhcp_discover(rx[0], self.pg3, hostname,
+                                       dscp=vdscp.IP_API_DSCP_EF)
+
+        self.vapi.dhcp_client_config(vlan_100.sw_if_index,
+                                     hostname,
+                                     is_add=0)
+
 
 if __name__ == '__main__':
     unittest.main(testRunner=VppTestRunner)
index e40ef79..f9bb470 100644 (file)
@@ -1032,7 +1032,8 @@ class VppPapiProvider(object):
                            client_id='',
                            is_add=1,
                            set_broadcast_flag=1,
-                           want_dhcp_events=0):
+                           want_dhcp_events=0,
+                           dscp=0):
         return self.api(
             self.papi.dhcp_client_config,
             {
@@ -1043,6 +1044,7 @@ class VppPapiProvider(object):
                     'id': client_id,
                     'want_dhcp_event': want_dhcp_events,
                     'set_broadcast_flag': set_broadcast_flag,
+                    'dscp': dscp,
                     'pid': os.getpid()}
             })