aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeale Ranns <nranns@cisco.com>2019-07-19 14:01:02 +0000
committerDamjan Marion <dmarion@me.com>2019-07-26 13:27:14 +0000
commit038e1dfbdfd0bd785852c364011da0a1d828093e (patch)
tree4e3a039c240e9e91123ff363f909caabc4c909f4
parent08ac303e43492c8b25911340fb62811289dd3935 (diff)
dhcp ip: DSCP settings for transmitted DHCP packets
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>
-rw-r--r--extras/vom/vom/dhcp_client.cpp22
-rw-r--r--extras/vom/vom/dhcp_client.hpp7
-rw-r--r--extras/vom/vom/dhcp_client_cmds.cpp10
-rw-r--r--extras/vom/vom/dhcp_client_cmds.hpp8
-rw-r--r--extras/vom/vom/prefix.cpp31
-rw-r--r--extras/vom/vom/prefix.hpp39
-rw-r--r--extras/vom/vom/route_api_types.cpp71
-rw-r--r--extras/vom/vom/route_api_types.hpp3
-rw-r--r--src/vnet/dhcp/client.c21
-rw-r--r--src/vnet/dhcp/client.h6
-rw-r--r--src/vnet/dhcp/dhcp.api4
-rw-r--r--src/vnet/dhcp/dhcp_api.c15
-rw-r--r--src/vnet/ip/ip.c17
-rw-r--r--src/vnet/ip/ip4_packet.h2
-rw-r--r--src/vnet/ip/ip6_packet.h6
-rw-r--r--src/vnet/ip/ip_packet.h38
-rw-r--r--src/vnet/ip/ip_types.api2
-rw-r--r--src/vnet/ip/ip_types_api.c12
-rw-r--r--src/vnet/ip/ip_types_api.h2
-rw-r--r--src/vnet/mpls/packet.h10
-rw-r--r--test/test_dhcp.py72
-rw-r--r--test/vpp_papi_provider.py4
22 files changed, 356 insertions, 46 deletions
diff --git a/extras/vom/vom/dhcp_client.cpp b/extras/vom/vom/dhcp_client.cpp
index fcadfa69ded..e3a5b9d5559 100644
--- a/extras/vom/vom/dhcp_client.cpp
+++ b/extras/vom/vom/dhcp_client.cpp
@@ -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)));
diff --git a/extras/vom/vom/dhcp_client.hpp b/extras/vom/vom/dhcp_client.hpp
index 17c626ed0f1..8e8669a96ef 100644
--- a/extras/vom/vom/dhcp_client.hpp
+++ b/extras/vom/vom/dhcp_client.hpp
@@ -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);
/**
@@ -259,6 +261,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.
*/
diff --git a/extras/vom/vom/dhcp_client_cmds.cpp b/extras/vom/vom/dhcp_client_cmds.cpp
index 9b632fe88f9..c1d4d49a495 100644
--- a/extras/vom/vom/dhcp_client_cmds.cpp
+++ b/extras/vom/vom/dhcp_client_cmds.cpp
@@ -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());
}
diff --git a/extras/vom/vom/dhcp_client_cmds.hpp b/extras/vom/vom/dhcp_client_cmds.hpp
index 89fe7eefa73..10d4026f4f3 100644
--- a/extras/vom/vom/dhcp_client_cmds.hpp
+++ b/extras/vom/vom/dhcp_client_cmds.hpp
@@ -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;
};
/**
diff --git a/extras/vom/vom/prefix.cpp b/extras/vom/vom/prefix.cpp
index a6305997f53..45cb6df54c9 100644
--- a/extras/vom/vom/prefix.cpp
+++ b/extras/vom/vom/prefix.cpp
@@ -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
*/
diff --git a/extras/vom/vom/prefix.hpp b/extras/vom/vom/prefix.hpp
index b75dc66f86e..fada1d3e274 100644
--- a/extras/vom/vom/prefix.hpp
+++ b/extras/vom/vom/prefix.hpp
@@ -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
diff --git a/extras/vom/vom/route_api_types.cpp b/extras/vom/vom/route_api_types.cpp
index 31acc84b6fb..b6ab6381b12 100644
--- a/extras/vom/vom/route_api_types.cpp
+++ b/extras/vom/vom/route_api_types.cpp
@@ -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:
+ */
diff --git a/extras/vom/vom/route_api_types.hpp b/extras/vom/vom/route_api_types.hpp
index 25d0902cda1..e741a9d5acc 100644
--- a/extras/vom/vom/route_api_types.hpp
+++ b/extras/vom/vom/route_api_types.hpp
@@ -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
/*
diff --git a/src/vnet/dhcp/client.c b/src/vnet/dhcp/client.c
index 472de5253ef..aaeda96327d 100644
--- a/src/vnet/dhcp/client.c
+++ b/src/vnet/dhcp/client.c
@@ -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);
diff --git a/src/vnet/dhcp/client.h b/src/vnet/dhcp/client.h
index a79d6e59715..5191fcf0fa8 100644
--- a/src/vnet/dhcp/client.h
+++ b/src/vnet/dhcp/client.h
@@ -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
diff --git a/src/vnet/dhcp/dhcp.api b/src/vnet/dhcp/dhcp.api
index 033c7a34fed..6db9033a7f4 100644
--- a/src/vnet/dhcp/dhcp.api
+++ b/src/vnet/dhcp/dhcp.api
@@ -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;
};
diff --git a/src/vnet/dhcp/dhcp_api.c b/src/vnet/dhcp/dhcp_api.c
index 7eb2bf46a06..7935ad8ba01 100644
--- a/src/vnet/dhcp/dhcp_api.c
+++ b/src/vnet/dhcp/dhcp_api.c
@@ -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);
}
diff --git a/src/vnet/ip/ip.c b/src/vnet/ip/ip.c
index 6e8ac7c437d..133767bd06c 100644
--- a/src/vnet/ip/ip.c
+++ b/src/vnet/ip/ip.c
@@ -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
*
diff --git a/src/vnet/ip/ip4_packet.h b/src/vnet/ip/ip4_packet.h
index 2ce6763f8d7..c1852fc3ff2 100644
--- a/src/vnet/ip/ip4_packet.h
+++ b/src/vnet/ip/ip4_packet.h
@@ -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;
diff --git a/src/vnet/ip/ip6_packet.h b/src/vnet/ip/ip6_packet.h
index c8bc4c817e8..c1bd2aa3bf7 100644
--- a/src/vnet/ip/ip6_packet.h
+++ b/src/vnet/ip/ip6_packet.h
@@ -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);
diff --git a/src/vnet/ip/ip_packet.h b/src/vnet/ip/ip_packet.h
index c4990976188..97b3c96b2ce 100644
--- a/src/vnet/ip/ip_packet.h
+++ b/src/vnet/ip/ip_packet.h
@@ -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
diff --git a/src/vnet/ip/ip_types.api b/src/vnet/ip/ip_types.api
index 8b46a1d44fe..13c6a4aab28 100644
--- a/src/vnet/ip/ip_types.api
+++ b/src/vnet/ip/ip_types.api
@@ -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,
diff --git a/src/vnet/ip/ip_types_api.c b/src/vnet/ip/ip_types_api.c
index 0343d2001ad..ca26731a30a 100644
--- a/src/vnet/ip/ip_types_api.c
+++ b/src/vnet/ip/ip_types_api.c
@@ -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)
{
diff --git a/src/vnet/ip/ip_types_api.h b/src/vnet/ip/ip_types_api.h
index 4c79bf138e3..fc7a416a06d 100644
--- a/src/vnet/ip/ip_types_api.h
+++ b/src/vnet/ip/ip_types_api.h
@@ -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
diff --git a/src/vnet/mpls/packet.h b/src/vnet/mpls/packet.h
index ca6ac407686..8573bc3bef5 100644
--- a/src/vnet/mpls/packet.h
+++ b/src/vnet/mpls/packet.h
@@ -1,6 +1,3 @@
-#ifndef included_vnet_mpls_packet_h
-#define included_vnet_mpls_packet_h
-
/*
* MPLS packet format
*
@@ -18,6 +15,11 @@
* 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);
}
diff --git a/test/test_dhcp.py b/test/test_dhcp.py
index fce41a9b423..16b0f470b0a 100644
--- a/test/test_dhcp.py
+++ b/test/test_dhcp.py
@@ -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)
diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py
index e40ef79cbf2..f9bb470ec1d 100644
--- a/test/vpp_papi_provider.py
+++ b/test/vpp_papi_provider.py
@@ -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()}
})