From 038e1dfbdfd0bd785852c364011da0a1d828093e Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Fri, 19 Jul 2019 14:01:02 +0000 Subject: [PATCH] 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 --- extras/vom/vom/dhcp_client.cpp | 22 ++++++++---- extras/vom/vom/dhcp_client.hpp | 7 ++++ extras/vom/vom/dhcp_client_cmds.cpp | 10 ++++-- extras/vom/vom/dhcp_client_cmds.hpp | 8 ++++- extras/vom/vom/prefix.cpp | 31 ++++++++++++++++ extras/vom/vom/prefix.hpp | 39 ++++++++++++++++++++ extras/vom/vom/route_api_types.cpp | 71 ++++++++++++++++++++++++++++++++---- extras/vom/vom/route_api_types.hpp | 3 ++ src/vnet/dhcp/client.c | 21 ++++++++++- src/vnet/dhcp/client.h | 6 +++- src/vnet/dhcp/dhcp.api | 4 +++ src/vnet/dhcp/dhcp_api.c | 15 ++++---- src/vnet/ip/ip.c | 17 +++++++++ src/vnet/ip/ip4_packet.h | 2 +- src/vnet/ip/ip6_packet.h | 6 ++-- src/vnet/ip/ip_packet.h | 38 ++++++++++++++++++++ src/vnet/ip/ip_types.api | 2 +- src/vnet/ip/ip_types_api.c | 12 +++++++ src/vnet/ip/ip_types_api.h | 2 ++ src/vnet/mpls/packet.h | 10 +++--- test/test_dhcp.py | 72 +++++++++++++++++++++++++++++++------ test/vpp_papi_provider.py | 4 ++- 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(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( 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); /** @@ -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. 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& 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(v, s) +{ +} +ip_dscp_t::ip_dscp_t(int v) + : enum_base(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 +{ +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((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 #include #include +#include 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 #include #include +#include #include @@ -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 + /** * 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()} }) -- 2.16.6