diff --git a/Makefile b/Makefile index 59903ce92..e5e982638 100644 --- a/Makefile +++ b/Makefile @@ -69,7 +69,7 @@ ifneq ($(KERNELRELEASE), ) vrouter-y += dp-core/vr_bridge.o dp-core/vr_htable.o vrouter-y += dp-core/vr_vxlan.o dp-core/vr_fragment.o vrouter-y += dp-core/vr_proto_ip6.o dp-core/vr_buildinfo.o - vrouter-y += dp-core/vr_bitmap.o + vrouter-y += dp-core/vr_bitmap.o dp-core/vr_qos.o ccflags-y += -I$(src)/include -I$(SANDESH_HEADER_PATH)/sandesh/gen-c ccflags-y += -I$(SANDESH_EXTRA_HEADER_PATH) diff --git a/dp-core/vr_bridge.c b/dp-core/vr_bridge.c index 9afcb21fb..60a1d342c 100644 --- a/dp-core/vr_bridge.c +++ b/dp-core/vr_bridge.c @@ -461,6 +461,16 @@ vr_bridge_input(struct vrouter *router, struct vr_packet *pkt, } } + if (fmd->fmd_dscp < 0) { + if (pkt->vp_type == VP_TYPE_IP) { + fmd->fmd_dscp = + vr_inet_get_tos((struct vr_ip *)pkt_network_header(pkt)); + } else if (pkt->vp_type == VP_TYPE_IP6) { + fmd->fmd_dscp = + vr_inet6_get_tos((struct vr_ip6 *)pkt_network_header(pkt)); + } + } + /* Do the bridge lookup for the packets not meant for "me" */ if (!fmd->fmd_to_me) { diff --git a/dp-core/vr_flow.c b/dp-core/vr_flow.c index a49a03c1e..fd0c5c696 100644 --- a/dp-core/vr_flow.c +++ b/dp-core/vr_flow.c @@ -296,7 +296,7 @@ vr_flow_get_va(struct vrouter *router, uint64_t offset) } static struct vr_flow_entry * -__vr_get_flow_entry(struct vrouter *router, int index) +__vr_flow_get_entry(struct vrouter *router, int index) { struct vr_flow_entry *fe; @@ -312,7 +312,7 @@ __vr_get_flow_entry(struct vrouter *router, int index) } struct vr_flow_entry * -vr_get_flow_entry(struct vrouter *router, int index) +vr_flow_get_entry(struct vrouter *router, int index) { if (index < 0) return NULL; @@ -414,7 +414,7 @@ vr_flow_defer_cb(struct vrouter *router, void *arg) if (vfdd->vfdd_delete) { vr_flow_reset_entry(router, fe); } else { - rfe = vr_get_flow_entry(router, fe->fe_rflow); + rfe = vr_flow_get_entry(router, fe->fe_rflow); vr_flow_evict_flow(router, fe); if (rfe) vr_flow_evict_flow(router, rfe); @@ -454,7 +454,7 @@ vr_flow_defer(struct vr_flow_md *flmd, struct vr_flow_entry *fe) if (!vdd || !vdd->vdd_data) { if (flmd->flmd_flags & VR_FLOW_FLAG_EVICT_CANDIDATE) { if (fe->fe_rflow) { - rfe = vr_get_flow_entry(flmd->flmd_router, fe->fe_rflow); + rfe = vr_flow_get_entry(flmd->flmd_router, fe->fe_rflow); vr_flow_reset_evict(flmd->flmd_router, rfe); } vr_flow_reset_evict(flmd->flmd_router, fe); @@ -594,6 +594,7 @@ vr_flow_fill_pnode(struct vr_packet_node *pnode, struct vr_packet *pkt, pnode->pl_flags |= PN_FLAG_FRAGMENT_HEAD; } + pnode->pl_dscp = fmd->fmd_dscp; pnode->pl_vrf = fmd->fmd_dvrf; pnode->pl_vlan = fmd->fmd_vlan; @@ -656,7 +657,7 @@ vr_flow_set_forwarding_md(struct vrouter *router, struct vr_flow_entry *fe, md->fmd_ecmp_nh_index = fe->fe_ecmp_nh_index; md->fmd_udp_src_port = fe->fe_udp_src_port; if (fe->fe_flags & VR_RFLOW_VALID) { - rfe = vr_get_flow_entry(router, fe->fe_rflow); + rfe = vr_flow_get_entry(router, fe->fe_rflow); if (rfe) md->fmd_ecmp_src_nh_index = rfe->fe_ecmp_nh_index; } @@ -695,7 +696,7 @@ vr_flow_mark_evict(struct vrouter *router, struct vr_flow_entry *fe, } if (fe->fe_rflow >= 0) { - rfe = vr_get_flow_entry(router, fe->fe_rflow); + rfe = vr_flow_get_entry(router, fe->fe_rflow); if (rfe) { evict_forward_flow = false; if (rfe->fe_tcp_flags & VR_FLOW_TCP_DEAD) { @@ -746,6 +747,22 @@ vr_flow_mark_evict(struct vrouter *router, struct vr_flow_entry *fe, return; } +int16_t +vr_flow_get_qos(struct vrouter *router, struct vr_packet *pkt, + struct vr_forwarding_md *fmd) +{ + struct vr_flow_entry *fe; + + if (fmd->fmd_flow_index >= 0) { + fe = vr_flow_get_entry(router, fmd->fmd_flow_index); + if (fe) + return fe->fe_qos_id; + } + + return -1; +} + + static flow_result_t vr_flow_action(struct vrouter *router, struct vr_flow_entry *fe, unsigned int index, struct vr_packet *pkt, @@ -978,7 +995,7 @@ vr_flow_init_close(struct vrouter *router, struct vr_flow_entry *flow_e, struct vr_flow_entry *rfe; (void)__sync_fetch_and_or(&flow_e->fe_tcp_flags, VR_FLOW_TCP_DEAD); - rfe = vr_get_flow_entry(router, flow_e->fe_rflow); + rfe = vr_flow_get_entry(router, flow_e->fe_rflow); if (rfe) { (void)__sync_fetch_and_or(&rfe->fe_tcp_flags, VR_FLOW_TCP_DEAD); } @@ -1067,7 +1084,7 @@ vr_flow_tcp_digest(struct vrouter *router, struct vr_flow_entry *flow_e, (void)__sync_fetch_and_or(&flow_e->fe_tcp_flags, VR_FLOW_TCP_RST); if (flow_e->fe_flags & VR_RFLOW_VALID) { - rflow_e = vr_get_flow_entry(router, flow_e->fe_rflow); + rflow_e = vr_flow_get_entry(router, flow_e->fe_rflow); if (rflow_e) { (void)__sync_fetch_and_or(&rflow_e->fe_tcp_flags, VR_FLOW_TCP_RST); @@ -1080,7 +1097,7 @@ vr_flow_tcp_digest(struct vrouter *router, struct vr_flow_entry *flow_e, flow_e->fe_tcp_seq = ntohl(tcph->tcp_seq); (void)__sync_fetch_and_or(&flow_e->fe_tcp_flags, VR_FLOW_TCP_SYN); if (flow_e->fe_flags & VR_RFLOW_VALID) { - rflow_e = vr_get_flow_entry(router, flow_e->fe_rflow); + rflow_e = vr_flow_get_entry(router, flow_e->fe_rflow); if (rflow_e) { (void)__sync_fetch_and_or(&rflow_e->fe_tcp_flags, VR_FLOW_TCP_SYN_R); @@ -1114,7 +1131,7 @@ vr_flow_tcp_digest(struct vrouter *router, struct vr_flow_entry *flow_e, * tcp header has an ack bit set */ if (flow_e->fe_flags & VR_RFLOW_VALID) { - rflow_e = vr_get_flow_entry(router, flow_e->fe_rflow); + rflow_e = vr_flow_get_entry(router, flow_e->fe_rflow); if (rflow_e) { (void)__sync_fetch_and_or(&rflow_e->fe_tcp_flags, VR_FLOW_TCP_FIN_R); @@ -1138,7 +1155,7 @@ vr_flow_tcp_digest(struct vrouter *router, struct vr_flow_entry *flow_e, (tcp_offset_flags & VR_TCP_FLAG_ACK)) { if (flow_e->fe_flags & VR_RFLOW_VALID) { if (!rflow_e) { - rflow_e = vr_get_flow_entry(router, flow_e->fe_rflow); + rflow_e = vr_flow_get_entry(router, flow_e->fe_rflow); } if (rflow_e) { @@ -1348,6 +1365,7 @@ vr_flow_flush_pnode(struct vrouter *router, struct vr_packet_node *pnode, if (!pkt) return -EINVAL; + fmd->fmd_dscp = pnode->pl_dscp; pnode->pl_packet = NULL; /* * this is only a security check and not a catch all check. one note @@ -1457,7 +1475,7 @@ vr_flow_work(void *arg) if (!router) goto exit_flush; - fe = vr_get_flow_entry(router, flmd->flmd_index); + fe = vr_flow_get_entry(router, flmd->flmd_index); if (!fe) goto exit_flush; @@ -1652,7 +1670,7 @@ vr_flow_set_req_is_invalid(struct vrouter *router, vr_flow_req *req, } if (req->fr_flags & VR_RFLOW_VALID) { - rfe = vr_get_flow_entry(router, req->fr_rindex); + rfe = vr_flow_get_entry(router, req->fr_rindex); if (!rfe) { error = -EINVAL; goto invalid_req; @@ -1801,7 +1819,7 @@ vr_flow_set(struct vrouter *router, vr_flow_req *req) if (!router) return -EINVAL; - fe = vr_get_flow_entry(router, req->fr_index); + fe = vr_flow_get_entry(router, req->fr_index); if (fe) { if (!(modified = vr_flow_start_modify(router, fe))) return -EBUSY; @@ -1881,6 +1899,7 @@ vr_flow_set(struct vrouter *router, vr_flow_req *req) fe->fe_ecmp_nh_index = req->fr_ecmp_nh_index; fe->fe_src_nh_index = req->fr_src_nh_index; + fe->fe_qos_id = req->fr_qos_id; if ((req->fr_action == VR_FLOW_ACTION_HOLD) && (fe->fe_action != VR_FLOW_ACTION_HOLD)) { @@ -1907,7 +1926,7 @@ vr_flow_set(struct vrouter *router, vr_flow_req *req) } if (fe->fe_flags & VR_RFLOW_VALID) { - rfe = vr_get_flow_entry(router, fe->fe_rflow); + rfe = vr_flow_get_entry(router, fe->fe_rflow); if (rfe) { vr_flow_tcp_rflow_set(router, fe, rfe); } @@ -2139,7 +2158,7 @@ vr_flow_table_reset(struct vrouter *router) flmd.flmd_defer_data = NULL; vr_init_forwarding_md(&fmd); for (i = start; i < end; i++) { - fe = __vr_get_flow_entry(router, i); + fe = __vr_flow_get_entry(router, i); if (fe) { flmd.flmd_index = i; flmd.flmd_flags = fe->fe_flags; diff --git a/dp-core/vr_interface.c b/dp-core/vr_interface.c index 6b0ab74df..4835cd076 100644 --- a/dp-core/vr_interface.c +++ b/dp-core/vr_interface.c @@ -1745,6 +1745,7 @@ vr_interface_change(struct vr_interface *vif, vr_interface_req *req) vif->vif_mtu = req->vifr_mtu; vif->vif_nh_id = (unsigned short)req->vifr_nh_id; + vif->vif_qos_map_index = req->vifr_qos_map_index; if ((ret = vif_fat_flow_add(vif, req))) return ret; @@ -1835,6 +1836,7 @@ vr_interface_add(vr_interface_req *req, bool need_response) vif->vif_os_idx = 0; vif->vif_rid = req->vifr_rid; vif->vif_nh_id = (unsigned short)req->vifr_nh_id; + vif->vif_qos_map_index = req->vifr_qos_map_index; if (req->vifr_mac) { if (req->vifr_mac_size != sizeof(vif->vif_mac)) { @@ -2068,6 +2070,7 @@ __vr_interface_make_req(vr_interface_req *req, struct vr_interface *intf, } } + req->vifr_qos_map_index = intf->vif_qos_map_index; return; } diff --git a/dp-core/vr_mpls.c b/dp-core/vr_mpls.c index 096cd2aad..10c8a7aa6 100644 --- a/dp-core/vr_mpls.c +++ b/dp-core/vr_mpls.c @@ -297,12 +297,13 @@ int vr_mpls_input(struct vrouter *router, struct vr_packet *pkt, struct vr_forwarding_md *fmd) { + int ttl, l2_offset = 0; unsigned int label; unsigned short drop_reason; + struct vr_nexthop *nh; struct vr_ip *ip; struct vr_forwarding_md c_fmd; - int ttl, l2_offset = 0; if (!fmd) { vr_init_forwarding_md(&c_fmd); diff --git a/dp-core/vr_nexthop.c b/dp-core/vr_nexthop.c index 6a1ea7f5c..e0417a01b 100644 --- a/dp-core/vr_nexthop.c +++ b/dp-core/vr_nexthop.c @@ -335,8 +335,10 @@ nh_l3_rcv(struct vr_packet *pkt, struct vr_nexthop *nh, static int -nh_push_mpls_header(struct vr_packet *pkt, unsigned int label) +nh_push_mpls_header(struct vr_packet *pkt, unsigned int label, + struct vr_forwarding_class_qos *qos) { + uint32_t exp_qos = 0; unsigned int *lbl; unsigned int ttl; @@ -351,7 +353,13 @@ nh_push_mpls_header(struct vr_packet *pkt, unsigned int label) ttl = 64; } - *lbl = htonl((label << VR_MPLS_LABEL_SHIFT) | VR_MPLS_STACK_BIT | ttl); + if (qos) { + exp_qos = qos->vfcq_mpls_qos; + exp_qos <<= VR_MPLS_EXP_QOS_SHIFT; + } + + *lbl = htonl((label << VR_MPLS_LABEL_SHIFT) | exp_qos | + VR_MPLS_STACK_BIT | ttl); return 0; } @@ -362,8 +370,8 @@ nh_push_mpls_header(struct vr_packet *pkt, unsigned int label) */ static bool nh_udp_tunnel_helper(struct vr_packet *pkt, unsigned short sport, - unsigned short dport, unsigned int sip, - unsigned int dip) + unsigned short dport, unsigned int sip, + unsigned int dip, struct vr_forwarding_class_qos *qos) { struct vr_ip *ip; struct vr_udp *udp; @@ -387,7 +395,13 @@ nh_udp_tunnel_helper(struct vr_packet *pkt, unsigned short sport, ip->ip_version = 4; ip->ip_hl = 5; - ip->ip_tos = 0; + if (qos) { + ip->ip_tos = qos->vfcq_dscp; + pkt->vp_queue = qos->vfcq_queue_id + 1; + pkt->vp_priority = qos->vfcq_dotonep_qos; + } else { + ip->ip_tos = 0; + } ip->ip_id = htons(vr_generate_unique_ip_id()); ip->ip_frag_off = 0; @@ -479,12 +493,14 @@ nh_udp_tunnel6_helper(struct vr_packet *pkt, struct vr_nexthop *nh) } static bool -nh_vxlan_tunnel_helper(struct vr_packet *pkt, struct vr_forwarding_md *fmd, - unsigned int sip, unsigned int dip) +nh_vxlan_tunnel_helper(struct vrouter *router, struct vr_packet *pkt, + struct vr_forwarding_md *fmd, unsigned int sip, unsigned int dip) { unsigned short udp_src_port = VR_VXLAN_UDP_SRC_PORT; + struct vr_vxlan *vxlanh; struct vr_packet *tmp_pkt; + struct vr_forwarding_class_qos *qos; if (pkt_head_space(pkt) < VR_VXLAN_HDR_LEN) { tmp_pkt = vr_pexpand_head(pkt, VR_VXLAN_HDR_LEN - pkt_head_space(pkt)); @@ -514,8 +530,9 @@ nh_vxlan_tunnel_helper(struct vr_packet *pkt, struct vr_forwarding_md *fmd, vxlanh->vxlan_vnid = htonl(fmd->fmd_label << VR_VXLAN_VNID_SHIFT); vxlanh->vxlan_flags = htonl(VR_VXLAN_IBIT); + qos = vr_qos_get_forwarding_class(router, pkt, fmd); return nh_udp_tunnel_helper(pkt, htons(udp_src_port), - htons(VR_VXLAN_UDP_DST_PORT), sip, dip); + htons(VR_VXLAN_UDP_DST_PORT), sip, dip, qos); } static struct vr_packet * @@ -1323,7 +1340,8 @@ nh_composite_fabric(struct vr_packet *pkt, struct vr_nexthop *nh, */ vr_forwarding_md_set_label(fmd, label, VR_LABEL_TYPE_UNKNOWN); fmd->fmd_dvrf = dir_nh->nh_dev->vif_vrf; - if (nh_vxlan_tunnel_helper(new_pkt, fmd, sip, sip) == false) { + if (nh_vxlan_tunnel_helper(nh->nh_router, new_pkt, + fmd, sip, sip) == false) { vr_pfree(new_pkt, VP_DROP_PUSH); break; } @@ -1394,6 +1412,7 @@ nh_udp_tunnel(struct vr_packet *pkt, struct vr_nexthop *nh, struct vr_ip6 *ip6; struct vr_udp *udp; struct vr_vrf_stats *stats; + struct vr_forwarding_class_qos *qos; if (!fmd) goto send_fail; @@ -1424,9 +1443,10 @@ nh_udp_tunnel(struct vr_packet *pkt, struct vr_nexthop *nh, sip = nh->nh_udp_tun_sip; } + qos = vr_qos_get_forwarding_class(nh->nh_router, pkt, fmd); if (nh_udp_tunnel_helper(pkt, nh->nh_udp_tun_sport, nh->nh_udp_tun_dport, sip, - nh->nh_udp_tun_dip) == false) { + nh->nh_udp_tun_dip, qos) == false) { goto send_fail; } @@ -1525,8 +1545,8 @@ nh_vxlan_tunnel(struct vr_packet *pkt, struct vr_nexthop *nh, } } - if (nh_vxlan_tunnel_helper(pkt, fmd, nh->nh_udp_tun_sip, - nh->nh_udp_tun_dip) == false) + if (nh_vxlan_tunnel_helper(nh->nh_router, pkt, fmd, nh->nh_udp_tun_sip, + nh->nh_udp_tun_dip) == false) goto send_fail; pkt_set_network_header(pkt, pkt->vp_data); @@ -1589,12 +1609,14 @@ static int nh_mpls_udp_tunnel(struct vr_packet *pkt, struct vr_nexthop *nh, struct vr_forwarding_md *fmd) { - unsigned char *tun_encap; - struct vr_interface *vif; - struct vr_vrf_stats *stats; unsigned int tun_sip, tun_dip, overhead_len, mudp_head_space; uint16_t tun_encap_len, udp_src_port = VR_MPLS_OVER_UDP_SRC_PORT; unsigned short reason = VP_DROP_PUSH; + + unsigned char *tun_encap; + struct vr_forwarding_class_qos *qos; + struct vr_interface *vif; + struct vr_vrf_stats *stats; struct vr_packet *tmp_pkt; struct vr_df_trap_arg trap_arg; @@ -1665,7 +1687,8 @@ nh_mpls_udp_tunnel(struct vr_packet *pkt, struct vr_nexthop *nh, pkt = tmp_pkt; } - if (nh_push_mpls_header(pkt, fmd->fmd_label) < 0) + qos = vr_qos_get_forwarding_class(nh->nh_router, pkt, fmd); + if (nh_push_mpls_header(pkt, fmd->fmd_label, qos) < 0) goto send_fail; if (vr_perfs) @@ -1689,7 +1712,7 @@ nh_mpls_udp_tunnel(struct vr_packet *pkt, struct vr_nexthop *nh, if (nh_udp_tunnel_helper(pkt, htons(udp_src_port), htons(VR_MPLS_OVER_UDP_DST_PORT), - tun_sip, tun_dip) == false) { + tun_sip, tun_dip, qos) == false) { goto send_fail; } @@ -1727,12 +1750,14 @@ static int nh_gre_tunnel(struct vr_packet *pkt, struct vr_nexthop *nh, struct vr_forwarding_md *fmd) { - unsigned int id; int overhead_len, gre_head_space; unsigned short drop_reason = VP_DROP_INVALID_NH; + unsigned int id; + + unsigned char *tun_encap; + struct vr_forwarding_class_qos *qos; struct vr_gre *gre_hdr; struct vr_ip *ip; - unsigned char *tun_encap; struct vr_interface *vif; struct vr_vrf_stats *stats; struct vr_packet *tmp_pkt; @@ -1809,7 +1834,8 @@ nh_gre_tunnel(struct vr_packet *pkt, struct vr_nexthop *nh, pkt = tmp_pkt; } - if (nh_push_mpls_header(pkt, fmd->fmd_label) < 0) + qos = vr_qos_get_forwarding_class(nh->nh_router, pkt, fmd); + if (nh_push_mpls_header(pkt, fmd->fmd_label, qos) < 0) goto send_fail; gre_hdr = (struct vr_gre *)pkt_push(pkt, sizeof(struct vr_gre)); @@ -1842,7 +1868,14 @@ nh_gre_tunnel(struct vr_packet *pkt, struct vr_nexthop *nh, ip->ip_version = 4; ip->ip_hl = 5; - ip->ip_tos = 0; + if (qos) { + ip->ip_tos = qos->vfcq_dscp; + pkt->vp_queue = qos->vfcq_queue_id + 1; + pkt->vp_priority = qos->vfcq_dotonep_qos; + } else { + ip->ip_tos = 0; + } + ip->ip_id = id; ip->ip_frag_off = 0; @@ -1958,6 +1991,7 @@ nh_encap_l2(struct vr_packet *pkt, struct vr_nexthop *nh, { struct vr_interface *vif; struct vr_vrf_stats *stats; + struct vr_forwarding_class_qos *qos; /* No GRO for multicast and user packets */ if ((pkt->vp_flags & VP_FLAG_MULTICAST) || @@ -1965,14 +1999,30 @@ nh_encap_l2(struct vr_packet *pkt, struct vr_nexthop *nh, pkt->vp_flags &= ~VP_FLAG_GRO; vif = nh->nh_dev; - stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu); - if ((pkt->vp_flags & VP_FLAG_GRO) && vif_is_virtual(vif)) { - if (vr_gro_input(pkt, nh)) { - if (stats) - stats->vrf_gros++; - return 0; + if (!(pkt->vp_flags & VP_FLAG_GROED)) { + qos = vr_qos_get_forwarding_class(nh->nh_router, pkt, fmd); + if (qos) { + if (pkt->vp_type == VP_TYPE_IP) { + vr_inet_set_tos((struct vr_ip *)pkt_network_header(pkt), + qos->vfcq_dscp); + } else if (pkt->vp_type == VP_TYPE_IP6) { + vr_inet6_set_tos((struct vr_ip6 *)pkt_network_header(pkt), + qos->vfcq_dscp); + } + pkt->vp_queue = qos->vfcq_queue_id + 1; + pkt->vp_priority = qos->vfcq_dotonep_qos; + } + } + + if (pkt->vp_flags & VP_FLAG_GRO) { + if (vif_is_virtual(vif)) { + if (vr_gro_input(pkt, nh)) { + if (stats) + stats->vrf_gros++; + return 0; + } } } @@ -1998,19 +2048,33 @@ static int nh_encap_l3(struct vr_packet *pkt, struct vr_nexthop *nh, struct vr_forwarding_md *fmd) { + unsigned short *proto_p; + + struct vr_ip *ip; struct vr_interface *vif; struct vr_vrf_stats *stats; - struct vr_ip *ip; - unsigned short *proto_p; + struct vr_forwarding_class_qos *qos = NULL; stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu); vif = nh->nh_dev; + if (!(pkt->vp_flags & VP_FLAG_GROED)) { + qos = vr_qos_get_forwarding_class(nh->nh_router, pkt, fmd); + if (qos) { + pkt->vp_queue = qos->vfcq_queue_id; + pkt->vp_priority = qos->vfcq_dotonep_qos; + } + } + ip = (struct vr_ip *)pkt_network_header(pkt); if (vr_ip_is_ip6(ip)) { pkt->vp_type = VP_TYPE_IP6; + if (qos) + vr_inet6_set_tos((struct vr_ip6 *)ip, qos->vfcq_dscp); } else if (vr_ip_is_ip4(ip)) { pkt->vp_type = VP_TYPE_IP; + if (qos) + vr_inet_set_tos(ip, qos->vfcq_dscp); } else { vr_pfree(pkt, VP_DROP_INVALID_PROTOCOL); return 0; diff --git a/dp-core/vr_proto_ip.c b/dp-core/vr_proto_ip.c index ab9a97c46..7566fc58f 100644 --- a/dp-core/vr_proto_ip.c +++ b/dp-core/vr_proto_ip.c @@ -78,17 +78,11 @@ vr_inet_src_lookup(unsigned short vrf, struct vr_packet *pkt) static inline unsigned char vr_ip_decrement_ttl(struct vr_ip *ip) { - unsigned int diff = 0xfffe; - unsigned int csum; - - csum = (~ip->ip_csum) & 0xffff; - csum += diff; - csum = (csum >> 16) + (csum & 0xffff); - if (csum >> 16) - csum = (csum & 0xffff) + 1; + unsigned int diff = 0; + vr_incremental_diff(ip->ip_ttl, ip->ip_ttl - 1, &diff); --ip->ip_ttl; - ip->ip_csum = ~(csum & 0xffff); + vr_ip_incremental_csum(ip, diff); return ip->ip_ttl; } @@ -496,18 +490,22 @@ int vr_ip_rcv(struct vrouter *router, struct vr_packet *pkt, struct vr_forwarding_md *fmd) { - struct vr_ip *ip; - struct vr_interface *vif = NULL; - unsigned char *l2_hdr; unsigned int hlen; unsigned short drop_reason, l4_port = 0; int ret = 0, unhandled = 1; + + struct vr_ip *ip; + unsigned char *l2_hdr; struct vr_fragment *frag; + struct vr_interface *vif = NULL; + struct vr_forwarding_class_qos *qos; ip = (struct vr_ip *)pkt_data(pkt); hlen = ip->ip_hl * 4; pkt_pull(pkt, hlen); + qos = vr_qos_get_forwarding_class(router, pkt, fmd); + /* * this is a check to make sure that packets were indeed destined to * me or not. there are two ways a packet can reach here. either through @@ -586,6 +584,12 @@ vr_ip_rcv(struct vrouter *router, struct vr_packet *pkt, } } + if (qos) { + vr_inet_set_tos(ip, qos->vfcq_dscp); + pkt->vp_queue = qos->vfcq_queue_id + 1; + pkt->vp_priority = qos->vfcq_dotonep_qos; + } + if (!vif && !(vif = pkt->vp_if->vif_bridge) && !(vif = router->vr_host_if)) { drop_reason = VP_DROP_TRAP_NO_IF; @@ -637,7 +641,7 @@ vr_inet_flow_nat(struct vr_flow_entry *fe, struct vr_packet *pkt, if (fe->fe_rflow < 0) goto drop; - rfe = vr_get_flow_entry(router, fe->fe_rflow); + rfe = vr_flow_get_entry(router, fe->fe_rflow); if (!rfe) goto drop; @@ -1128,6 +1132,9 @@ vr_ip_input(struct vrouter *router, struct vr_packet *pkt, if (pkt->vp_flags & VP_FLAG_TO_ME) return vr_ip_rcv(router, pkt, fmd); + if (fmd->fmd_dscp < 0) + fmd->fmd_dscp = vr_inet_get_tos(ip); + if (!vr_flow_forward(router, pkt, fmd)) return 0; diff --git a/dp-core/vr_proto_ip6.c b/dp-core/vr_proto_ip6.c index e104f1679..27d9f0cc5 100644 --- a/dp-core/vr_proto_ip6.c +++ b/dp-core/vr_proto_ip6.c @@ -291,6 +291,9 @@ vr_ip6_input(struct vrouter *router, struct vr_packet *pkt, unsigned short *t_hdr, sport, dport; ip6 = (struct vr_ip6 *)pkt_network_header(pkt); + if (fmd->fmd_dscp < 0) + fmd->fmd_dscp = vr_inet6_get_tos(ip6); + t_hdr = (unsigned short *)((char *)ip6 + sizeof(struct vr_ip6)); if (!pkt_pull(pkt, sizeof(struct vr_ip6))) { diff --git a/dp-core/vr_qos.c b/dp-core/vr_qos.c new file mode 100644 index 000000000..5ddd38e73 --- /dev/null +++ b/dp-core/vr_qos.c @@ -0,0 +1,836 @@ +/* + * vr_qos.c -- QOS implementation for vRouter datapath + * + * Copyright (c) 2015, Juniper Networks Inc. + * All rights reserved + */ +#include +#include +#include + +#include "vr_message.h" +#include "vr_sandesh.h" +#include "vr_interface.h" +#include "vr_datapath.h" +#include "vr_qos.h" + +unsigned int vr_qos_map_entries = VR_DEF_QOS_MAP_ENTRIES; +unsigned int vr_fc_map_entries = VR_DEF_FC_MAP_ENTRIES; +unsigned int vr_qos_map_entry_size = VR_QOS_MAP_ENTRY_SIZE; + +static void +vr_qos_message_error(int error) +{ + vr_send_response(error); + return; +} + +unsigned int +vr_qos_map_req_get_size(void *object) +{ + unsigned int size; + vr_qos_map_req *req = (vr_qos_map_req *)object; + + size = 4 * sizeof(*req); + size += 4 * req->qmr_dscp_size; + size += 4 * req->qmr_dscp_fc_id_size; + size += 4 * req->qmr_mpls_qos_size; + size += 4 * req->qmr_mpls_qos_fc_id_size; + size += 4 * req->qmr_dotonep_size; + size += 4 * req->qmr_dotonep_fc_id_size; + + return size; +} + +static int +vr_qos_map_request_validate(vr_qos_map_req *req) +{ + if (req->qmr_id >= vr_qos_map_entries) + return -EINVAL; + + if (req->qmr_dscp_size != req->qmr_dscp_fc_id_size) + return -EINVAL; + + if (req->qmr_mpls_qos_size != req->qmr_mpls_qos_fc_id_size) + return -EINVAL; + + if (req->qmr_dotonep_size != req->qmr_dotonep_fc_id_size) + return -EINVAL; + + return 0; +} + +static struct vr_forwarding_class * +vr_qos_map_get_fc(struct vrouter *router, unsigned int id) +{ + if (id >= vr_qos_map_entries) + return NULL; + + return router->vr_qos_map[id]; +} + +static int +vr_qos_map_set_fc(struct vrouter *router, unsigned int id, + struct vr_forwarding_class *fc_p) +{ + if (id >= vr_qos_map_entries) + return -EINVAL; + + router->vr_qos_map[id] = fc_p; + return 0; +} + +static void +vr_qos_map_req_destroy(vr_qos_map_req *req) +{ + if (!req) + return; + + if (req->qmr_dscp && req->qmr_dscp_size) { + vr_free(req->qmr_dscp, VR_QOS_MAP_OBJECT); + req->qmr_dscp = NULL; + req->qmr_dscp_size = 0; + if (req->qmr_dscp_fc_id) { + vr_free(req->qmr_dscp_fc_id, VR_QOS_MAP_OBJECT); + req->qmr_dscp_fc_id_size = 0; + } + } + + if (req->qmr_mpls_qos && req->qmr_mpls_qos_size) { + vr_free(req->qmr_mpls_qos, VR_QOS_MAP_OBJECT); + req->qmr_mpls_qos = NULL; + req->qmr_mpls_qos_size = 0; + if (req->qmr_mpls_qos_fc_id) { + vr_free(req->qmr_mpls_qos_fc_id, VR_QOS_MAP_OBJECT); + req->qmr_mpls_qos_fc_id = NULL; + req->qmr_mpls_qos_fc_id_size = 0; + } + } + + if (req->qmr_dotonep && req->qmr_dotonep_size) { + vr_free(req->qmr_dotonep, VR_QOS_MAP_OBJECT); + req->qmr_dotonep = NULL; + req->qmr_dotonep_size = 0; + if (req->qmr_dotonep_fc_id) { + vr_free(req->qmr_dotonep_fc_id, VR_QOS_MAP_OBJECT); + req->qmr_dotonep_fc_id = NULL; + req->qmr_dotonep_fc_id_size = 0; + } + } + + vr_free(req, VR_QOS_MAP_OBJECT); + return; +} + +static vr_qos_map_req * +vr_qos_map_req_get(void) +{ + vr_qos_map_req *req; + + req = vr_zalloc(sizeof(vr_qos_map_req), VR_QOS_MAP_OBJECT); + if (!req) + return NULL; + + req->qmr_dscp = + vr_zalloc(sizeof(uint8_t) * VR_DSCP_QOS_ENTRIES, VR_QOS_MAP_OBJECT); + if (!req->qmr_dscp) { + goto alloc_failure; + } + req->qmr_dscp_size = VR_DSCP_QOS_ENTRIES; + + req->qmr_dscp_fc_id = + vr_zalloc(sizeof(uint8_t) * VR_DSCP_QOS_ENTRIES, VR_QOS_MAP_OBJECT); + if (!req->qmr_dscp_fc_id) { + goto alloc_failure; + } + req->qmr_dscp_fc_id_size = VR_DSCP_QOS_ENTRIES; + + req->qmr_mpls_qos = + vr_zalloc(sizeof(uint8_t) * VR_MPLS_QOS_ENTRIES, VR_QOS_MAP_OBJECT); + if (!req->qmr_mpls_qos) { + goto alloc_failure; + } + req->qmr_mpls_qos_size = VR_MPLS_QOS_ENTRIES; + + req->qmr_mpls_qos_fc_id = + vr_zalloc(sizeof(uint8_t) * VR_MPLS_QOS_ENTRIES, VR_QOS_MAP_OBJECT); + if (!req->qmr_mpls_qos_fc_id) { + goto alloc_failure; + } + req->qmr_mpls_qos_fc_id_size = VR_MPLS_QOS_ENTRIES; + + req->qmr_dotonep = + vr_zalloc(sizeof(uint8_t) * VR_DOTONEP_QOS_ENTRIES, VR_QOS_MAP_OBJECT); + if (!req->qmr_dotonep) { + goto alloc_failure; + } + req->qmr_dotonep_size = VR_DOTONEP_QOS_ENTRIES; + + req->qmr_dotonep_fc_id = + vr_zalloc(sizeof(uint8_t) * VR_DOTONEP_QOS_ENTRIES, VR_QOS_MAP_OBJECT); + if (!req->qmr_dotonep_fc_id) { + goto alloc_failure; + } + req->qmr_dotonep_fc_id_size = VR_DOTONEP_QOS_ENTRIES; + + return req; + +alloc_failure: + vr_qos_map_req_destroy(req); + return NULL; +} + +static void +vr_qos_map_make_req(unsigned int qmrid, vr_qos_map_req *resp, + struct vr_forwarding_class *fc_p) +{ + unsigned int i; + + resp->qmr_id = qmrid; + + for (i = 0; i < VR_DSCP_QOS_ENTRIES; i++) { + if (!fc_p[i].vfc_valid) + continue; + + resp->qmr_dscp[i] = fc_p[i].vfc_dscp; + resp->qmr_dscp_fc_id[i] = fc_p[i].vfc_id; + } + + for (i = 0; i < VR_MPLS_QOS_ENTRIES; i++) { + if (!fc_p[i].vfc_valid) + continue; + + resp->qmr_mpls_qos[i] = fc_p[VR_DSCP_QOS_ENTRIES + i].vfc_mpls_qos; + resp->qmr_mpls_qos_fc_id[i] = fc_p[VR_DSCP_QOS_ENTRIES + i].vfc_id; + } + + for (i = 0; i < VR_DOTONEP_QOS_ENTRIES; i++) { + if (!fc_p[i].vfc_valid) + continue; + + resp->qmr_dotonep[i] = + fc_p[VR_DSCP_QOS_ENTRIES + VR_MPLS_QOS_ENTRIES + i].vfc_dotonep_qos; + resp->qmr_dotonep_fc_id[i] = + fc_p[VR_DSCP_QOS_ENTRIES + VR_MPLS_QOS_ENTRIES + i].vfc_id; + } + + return; +} + +static void +vr_qos_map_free_fc_cb(struct vrouter *router, void *data) +{ + struct vr_defer_data *defer = (struct vr_defer_data *)data; + + if (!defer) + return; + + vr_free(defer->vdd_data, VR_QOS_MAP_OBJECT); + return; +} + +static int +vr_qos_map_free_fc_defer(struct vrouter *router, + struct vr_forwarding_class *fc_p) +{ + struct vr_defer_data *defer; + + defer = vr_get_defer_data(sizeof(*defer)); + if (!defer) + return -ENOMEM; + + defer->vdd_data = fc_p; + vr_defer(router, vr_qos_map_free_fc_cb, (void *)defer); + + return 0; +} + +static void +vr_qos_map_delete(vr_qos_map_req *req) +{ + int ret = 0; + + struct vr_forwarding_class *fc_p; + struct vrouter *router = vrouter_get(req->qmr_rid); + + if (req->qmr_id >= vr_qos_map_entries) { + ret = -EINVAL; + goto generate_response; + } + + fc_p = vr_qos_map_get_fc(router, req->qmr_id); + if (!fc_p) { + ret = 0; + goto generate_response; + } + + vr_qos_map_set_fc(router, req->qmr_id, NULL); + if (vr_qos_map_free_fc_defer(router, fc_p)) { + vr_delay_op(); + vr_free(fc_p, VR_QOS_MAP_OBJECT); + } + +generate_response: + vr_send_response(ret); + return; +} + +static void +vr_qos_map_dump(vr_qos_map_req *req) +{ + int ret = 0; + unsigned int i; + + vr_qos_map_req *resp; + struct vr_forwarding_class *fc_p; + struct vrouter *router = vrouter_get(req->qmr_rid); + struct vr_message_dumper *dumper = NULL; + + if (req->qmr_marker + 1 >= vr_qos_map_entries) + goto generate_response; + + dumper = vr_message_dump_init(req); + if (!dumper) { + ret = -ENOMEM; + goto generate_response; + } + + for (i = (req->qmr_marker + 1); i < vr_qos_map_entries; i++) { + fc_p = vr_qos_map_get_fc(router, i); + if (!fc_p) + continue; + + resp = vr_qos_map_req_get(); + if (!resp) { + ret = -ENOMEM; + goto generate_response; + } + + vr_qos_map_make_req(i, resp, fc_p); + ret = vr_message_dump_object(dumper, VR_QOS_MAP_OBJECT_ID, resp); + vr_qos_map_req_destroy(resp); + if (ret <= 0) + break; + } + +generate_response: + vr_message_dump_exit(dumper, ret); + return; +} + +static void +vr_qos_map_get(vr_qos_map_req *req) +{ + int ret = 0; + + vr_qos_map_req *resp; + struct vrouter *router = vrouter_get(req->qmr_rid); + struct vr_forwarding_class *fc_p = NULL; + + if (req->qmr_id >= vr_qos_map_entries) { + ret = -EINVAL; + goto get_error; + } + + fc_p = vr_qos_map_get_fc(router, req->qmr_id); + if (!fc_p) { + ret = -ENOENT; + goto get_error; + } + + resp = vr_qos_map_req_get(); + if (!resp) { + ret = -ENOMEM; + goto get_error; + } + + vr_qos_map_make_req(req->qmr_id, resp, fc_p); + vr_message_response(VR_QOS_MAP_OBJECT_ID, resp, ret); + if (resp) { + vr_qos_map_req_destroy(resp); + } + + return; + +get_error: + vr_send_response(ret); + return; +} + +static void +vr_qos_map_add(vr_qos_map_req *req) +{ + int ret = 0; + bool need_set = false; + unsigned int size, i; + + struct vrouter *router = vrouter_get(req->qmr_rid); + struct vr_forwarding_class *fc_p, *fc_e; + + ret = vr_qos_map_request_validate(req); + if (ret) { + goto generate_response; + } + + fc_p = vr_qos_map_get_fc(router, req->qmr_id); + if (!fc_p) { + size = vr_qos_map_entry_size * sizeof(struct vr_forwarding_class); + fc_p = vr_zalloc(size, VR_QOS_MAP_OBJECT); + if (!fc_p) { + ret = -ENOMEM; + goto generate_response; + } + need_set = true; + } + + for (i = 0; i < req->qmr_dscp_size; i++) { + if (req->qmr_dscp[i] >= VR_DSCP_QOS_ENTRIES) + continue; + + fc_e = &fc_p[req->qmr_dscp[i]]; + fc_e->vfc_dscp = req->qmr_dscp[i]; + fc_e->vfc_id = req->qmr_dscp_fc_id[i]; + fc_e->vfc_valid = 1; + } + + for (i = 0; i < req->qmr_mpls_qos_size; i++) { + if (req->qmr_mpls_qos[i] >= VR_MPLS_QOS_ENTRIES) + continue; + + fc_e = &fc_p[VR_DSCP_QOS_ENTRIES + req->qmr_mpls_qos[i]]; + fc_e->vfc_mpls_qos = req->qmr_mpls_qos[i]; + fc_e->vfc_id = req->qmr_mpls_qos_fc_id[i]; + fc_e->vfc_valid = 1; + } + + for (i = 0; i < req->qmr_dotonep_size; i++) { + if (req->qmr_dotonep[i] >= VR_DOTONEP_QOS_ENTRIES) + continue; + + fc_e = &fc_p[VR_DSCP_QOS_ENTRIES + VR_MPLS_QOS_ENTRIES + + req->qmr_dotonep[i]]; + fc_e->vfc_dotonep_qos = req->qmr_dotonep[i]; + fc_e->vfc_id = req->qmr_dotonep_fc_id[i]; + fc_e->vfc_valid = 1; + } + + if (need_set) { + vr_qos_map_set_fc(router, req->qmr_id, fc_p); + } + +generate_response: + vr_send_response(ret); + return; +} + +void +vr_qos_map_req_process(void *s_req) +{ + vr_qos_map_req *req = (vr_qos_map_req *)s_req; + + switch (req->h_op) { + case SANDESH_OP_ADD: + vr_qos_map_add(req); + break; + + case SANDESH_OP_GET: + vr_qos_map_get(req); + break; + + case SANDESH_OP_DUMP: + vr_qos_map_dump(req); + break; + + case SANDESH_OP_DELETE: + vr_qos_map_delete(req); + break; + + default: + vr_qos_message_error(-EINVAL); + break; + } + + return; +} + +struct vr_forwarding_class * +vr_fc_map_get_fc(struct vrouter *router, unsigned int i) +{ + if (i >= vr_fc_map_entries) + return NULL; + + return &router->vr_fc_table[i]; +} + +static void +vr_fc_map_req_destroy(vr_fc_map_req *req) +{ + if (!req) + return; + + if (req->fmr_id) { + vr_free(req->fmr_id, VR_FC_OBJECT); + req->fmr_id_size = 0; + } + + if (req->fmr_dscp) { + vr_free(req->fmr_dscp, VR_FC_OBJECT); + req->fmr_dscp_size = 0; + } + + if (req->fmr_mpls_qos) { + vr_free(req->fmr_mpls_qos, VR_FC_OBJECT); + req->fmr_mpls_qos_size = 0; + } + + if (req->fmr_dotonep) { + vr_free(req->fmr_dotonep, VR_FC_OBJECT); + req->fmr_dotonep_size = 0; + } + + if (req->fmr_queue_id) { + vr_free(req->fmr_queue_id, VR_FC_OBJECT); + req->fmr_queue_id_size = 0; + } + + vr_free(req, VR_FC_OBJECT); + return; +} + +static vr_fc_map_req * +vr_fc_map_req_get(unsigned int entries) +{ + vr_fc_map_req *req; + + req = vr_zalloc(sizeof(*req), VR_FC_OBJECT); + if (!req) + return NULL; + + req->fmr_id = vr_zalloc(entries, VR_FC_OBJECT); + if (!req->fmr_id) { + goto error; + } + req->fmr_id_size = entries; + + req->fmr_dscp = vr_zalloc(entries, VR_FC_OBJECT); + if (!req->fmr_dscp) { + goto error; + } + req->fmr_dscp_size = entries; + + req->fmr_mpls_qos = vr_zalloc(entries, VR_FC_OBJECT); + if (!req->fmr_mpls_qos) { + goto error; + } + req->fmr_mpls_qos_size = entries; + + req->fmr_dotonep = vr_zalloc(entries, VR_FC_OBJECT); + if (!req->fmr_dotonep) { + goto error; + } + req->fmr_dotonep_size = entries; + + req->fmr_queue_id = vr_zalloc(entries, VR_FC_OBJECT); + if (!req->fmr_queue_id) { + goto error; + } + req->fmr_queue_id_size = entries; + + return req; + +error: + vr_fc_map_req_destroy(req); + return NULL; +} + +static void +vr_fc_map_delete(vr_fc_map_req *req) +{ + int ret = 0; + + struct vrouter *router = vrouter_get(req->fmr_rid); + struct vr_forwarding_class *fc_p; + + if (!req->fmr_id) { + ret = -EINVAL; + goto generate_response; + } + + if (req->fmr_id[0] >= vr_fc_map_entries) { + ret = -EINVAL; + goto generate_response; + } + + fc_p = vr_fc_map_get_fc(router, req->fmr_id[0]); + if (!fc_p) { + ret = -EINVAL; + goto generate_response; + } + + memset(fc_p, 0, sizeof(*fc_p)); + vr_send_response(0); + + return; + +generate_response: + vr_send_response(ret); + return; +} + +static void +vr_fc_map_dump(vr_fc_map_req *req) +{ + int ret = 0; + unsigned int i; + + vr_fc_map_req *resp; + struct vr_forwarding_class *fc_p; + struct vrouter *router = vrouter_get(req->fmr_rid); + struct vr_message_dumper *dumper = NULL; + + if (req->fmr_marker + 1 >= vr_fc_map_entries) + goto generate_response; + + dumper = vr_message_dump_init(req); + if (!dumper) { + ret = -ENOMEM; + goto generate_response; + } + + for (i = (req->fmr_marker + 1); i < vr_fc_map_entries; i++) { + fc_p = vr_fc_map_get_fc(router, i); + if (!fc_p || !fc_p->vfc_valid) + continue; + + resp = vr_fc_map_req_get(1); + if (!resp) { + ret = -ENOMEM; + goto generate_response; + } + + resp->fmr_id[0] = i; + resp->fmr_dscp[0] = fc_p->vfc_dscp; + resp->fmr_mpls_qos[0] = fc_p->vfc_mpls_qos; + resp->fmr_dotonep[0] = fc_p->vfc_dotonep_qos; + resp->fmr_queue_id[0] = fc_p->vfc_queue_id; + + ret = vr_message_dump_object(dumper, VR_FC_MAP_OBJECT_ID, resp); + vr_fc_map_req_destroy(resp); + if (ret <= 0) + break; + } + +generate_response: + vr_message_dump_exit(dumper, ret); + return; +} + +static void +vr_fc_map_get(vr_fc_map_req *req) +{ + int ret = 0; + + vr_fc_map_req *resp; + struct vrouter *router = vrouter_get(req->fmr_rid); + struct vr_forwarding_class *fc_p; + + if (!req->fmr_id) { + ret = -EINVAL; + goto generate_response; + } + + if (req->fmr_id[0] >= vr_fc_map_entries) { + ret = -EINVAL; + goto generate_response; + } + + fc_p = vr_fc_map_get_fc(router, req->fmr_id[0]); + if (!fc_p || !fc_p->vfc_valid) { + ret = -ENOENT; + goto generate_response; + } + + resp = vr_fc_map_req_get(1); + if (!resp) { + ret = -ENOMEM; + goto generate_response; + } + + resp->fmr_id[0] = req->fmr_id[0]; + resp->fmr_dscp[0] = fc_p->vfc_dscp; + resp->fmr_mpls_qos[0] = fc_p->vfc_mpls_qos; + resp->fmr_dotonep[0] = fc_p->vfc_dotonep_qos; + resp->fmr_queue_id[0] = fc_p->vfc_queue_id; + +generate_response: + vr_message_response(VR_FC_MAP_OBJECT_ID, ret < 0 ? NULL : resp, ret); + if (resp) + vr_fc_map_req_destroy(resp); + + return; +} + +static void +vr_fc_map_add(vr_fc_map_req *req) +{ + int ret = 0; + unsigned int i; + + struct vrouter *router = vrouter_get(req->fmr_rid); + struct vr_forwarding_class *fc_p; + + if (!req->fmr_id || !req->fmr_id_size || + !req->fmr_dscp || !req->fmr_dscp_size || + !req->fmr_mpls_qos || !req->fmr_mpls_qos_size || + !req->fmr_dotonep || !req->fmr_dotonep_size || + !req->fmr_queue_id || !req->fmr_queue_id_size) { + ret = -EINVAL; + goto generate_response; + } + + for (i = 0; i < req->fmr_id_size; i++) { + fc_p = vr_fc_map_get_fc(router, req->fmr_id[i]); + if (!fc_p) { + ret = -EINVAL; + goto generate_response; + } + + fc_p->vfc_id = req->fmr_id[i]; + fc_p->vfc_dscp = req->fmr_dscp[i]; + fc_p->vfc_mpls_qos = req->fmr_mpls_qos[i]; + fc_p->vfc_dotonep_qos = req->fmr_dotonep[i]; + fc_p->vfc_queue_id = req->fmr_queue_id[i]; + fc_p->vfc_valid = 1; + } + +generate_response: + vr_send_response(ret); + return; +} + +void +vr_fc_map_req_process(void *s_req) +{ + vr_fc_map_req *req = (vr_fc_map_req *)s_req; + + switch (req->h_op) { + case SANDESH_OP_ADD: + vr_fc_map_add(req); + break; + + case SANDESH_OP_GET: + vr_fc_map_get(req); + break; + + case SANDESH_OP_DUMP: + vr_fc_map_dump(req); + break; + + case SANDESH_OP_DELETE: + vr_fc_map_delete(req); + break; + + default: + vr_qos_message_error(-EINVAL); + break; + } + + return; +} + +struct vr_forwarding_class_qos * +vr_qos_get_forwarding_class(struct vrouter *router, struct vr_packet *pkt, + struct vr_forwarding_md *fmd) +{ + uint8_t tos; + int16_t qos_id; + unsigned int fc_id; + + struct vr_interface *vif; + struct vr_forwarding_class *fc_p; + + if (fmd->fmd_flow_index >= 0) { + qos_id = vr_flow_get_qos(router, pkt, fmd); + } else { + vif = pkt->vp_if; + qos_id = vif->vif_qos_map_index; + } + + if (qos_id >= 0) { + fc_p = vr_qos_map_get_fc(router, qos_id); + if (!fc_p) + return NULL; + + tos = fmd->fmd_dscp; + if (tos >= 0) { + fc_id = fc_p[tos].vfc_id; + fc_p = vr_fc_map_get_fc(router, fc_id); + if (!fc_p->vfc_valid) + return NULL; + + return &fc_p->vfc_qos; + } + } + + return NULL; +} + +void +vr_qos_exit(struct vrouter *router, bool soft_reset) +{ + unsigned int i; + unsigned long size; + + if (soft_reset) { + size = vr_qos_map_entries * sizeof(struct vr_forwarding_class *); + if (router->vr_qos_map) { + memset(router->vr_qos_map, 0, size); + } + size = vr_fc_map_entries * sizeof(struct vr_forwarding_class); + if (router->vr_fc_table) { + memset(router->vr_fc_table, 0, size); + } + } else { + if (router->vr_qos_map) { + for (i = 0; i < vr_qos_map_entries; i++) { + if (router->vr_qos_map[i]) { + vr_free(router->vr_qos_map[i], VR_QOS_MAP_OBJECT); + router->vr_qos_map[i] = NULL; + } + } + vr_free(router->vr_qos_map, VR_QOS_MAP_OBJECT); + router->vr_qos_map = NULL; + } + + if (router->vr_fc_table) { + vr_free(router->vr_fc_table, VR_FC_OBJECT); + router->vr_fc_table = NULL; + } + } + + return; +} + +int +vr_qos_init(struct vrouter *router) +{ + unsigned long size; + + if (!router->vr_qos_map) { + size = vr_qos_map_entries * sizeof(struct vr_forwarding_class *); + router->vr_qos_map = vr_zalloc(size, VR_QOS_MAP_OBJECT); + if (!router->vr_qos_map) { + return vr_module_error(-ENOMEM, __FUNCTION__, __LINE__, size); + } + } + + if (!router->vr_fc_table) { + size = vr_fc_map_entries * sizeof(struct vr_forwarding_class); + router->vr_fc_table = vr_zalloc(size, VR_FC_OBJECT); + if (!router->vr_fc_table) { + return vr_module_error(-ENOMEM, __FUNCTION__, __LINE__, size); + } + } + + return 0; +} diff --git a/dp-core/vr_sandesh.c b/dp-core/vr_sandesh.c index 17f1308f8..80f5948dd 100644 --- a/dp-core/vr_sandesh.c +++ b/dp-core/vr_sandesh.c @@ -72,6 +72,15 @@ struct sandesh_object_md sandesh_md[] = { .obj_len = 4 * sizeof(vr_mem_stats_req), .obj_type_string = "vr_mem_stats_req", }, + [VR_QOS_MAP_OBJECT_ID] = { + .obj_len = 4 * sizeof(vr_qos_map_req), + .obj_get_size = vr_qos_map_req_get_size, + .obj_type_string = "vr_qos_map_req", + }, + [VR_FC_MAP_OBJECT_ID] = { + .obj_len = 4 * sizeof(vr_fc_map_req), + .obj_type_string = "vr_fc_map_req", + }, }; static unsigned int diff --git a/dp-core/vr_stats.c b/dp-core/vr_stats.c index 386117928..ad753ee3a 100644 --- a/dp-core/vr_stats.c +++ b/dp-core/vr_stats.c @@ -253,6 +253,11 @@ vr_mem_stats_get(void) stats_block[VR_USOCK_IOVEC_OBJECT].ms_free); response->vms_vrouter_req_object += (stats_block[VR_VROUTER_REQ_OBJECT].ms_alloc - stats_block[VR_VROUTER_REQ_OBJECT].ms_free); + response->vms_qos_map_object += (stats_block[VR_QOS_MAP_OBJECT].ms_alloc - + stats_block[VR_QOS_MAP_OBJECT].ms_free); + response->vms_fc_object += (stats_block[VR_FC_OBJECT].ms_alloc - + stats_block[VR_FC_OBJECT].ms_free); + for (i = 0; i < VR_VROUTER_MAX_OBJECT; i++) { alloced += stats_block[i].ms_alloc; freed += stats_block[i].ms_free; diff --git a/dp-core/vrouter.c b/dp-core/vrouter.c index f19230496..737a29ded 100644 --- a/dp-core/vrouter.c +++ b/dp-core/vrouter.c @@ -22,6 +22,7 @@ #include #include #include +#include static struct vrouter router; struct host_os *vrouter_host; @@ -95,6 +96,12 @@ static struct vr_module modules[] = { .init = vr_vxlan_init, .exit = vr_vxlan_exit, }, + { + .mod_name = "QOS", + .init = vr_qos_init, + .exit = vr_qos_exit, + }, + }; diff --git a/dpdk/vr_dpdk_host.c b/dpdk/vr_dpdk_host.c index 54edc97b4..66a355534 100644 --- a/dpdk/vr_dpdk_host.c +++ b/dpdk/vr_dpdk_host.c @@ -760,7 +760,7 @@ dpdk_get_udp_src_port(struct vr_packet *pkt, struct vr_forwarding_md *fmd, } if (fmd && fmd->fmd_flow_index >= 0) { - fentry = vr_get_flow_entry(router, fmd->fmd_flow_index); + fentry = vr_flow_get_entry(router, fmd->fmd_flow_index); if (fentry) { vr_dpdk_mbuf_reset(pkt); return fentry->fe_udp_src_port; diff --git a/include/nl_util.h b/include/nl_util.h index 134313445..a5e84b588 100644 --- a/include/nl_util.h +++ b/include/nl_util.h @@ -204,6 +204,17 @@ extern int vr_send_vxlan_get(struct nl_client *, unsigned int, unsigned int); extern int vr_send_vxlan_dump(struct nl_client *, unsigned int, int); extern int vr_send_vxlan_delete(struct nl_client *, unsigned int, unsigned int); +extern int vr_send_qos_map_get(struct nl_client *, unsigned int, unsigned int); +extern int vr_send_qos_map_dump(struct nl_client *, unsigned int, int); +extern int vr_send_qos_map_add(struct nl_client *, unsigned int, unsigned int, + uint8_t *, uint8_t, uint8_t *, uint8_t *, uint8_t, + uint8_t *, uint8_t *, uint8_t, uint8_t *); + +extern int vr_send_fc_map_get(struct nl_client *, unsigned int, uint8_t); +extern int vr_send_fc_map_dump(struct nl_client *, unsigned int, int); +extern int vr_send_fc_map_add(struct nl_client *, unsigned int, int16_t *, + uint8_t, uint8_t *, uint8_t *, uint8_t *, uint8_t *); + #ifdef __cplusplus diff --git a/include/vr_flow.h b/include/vr_flow.h index 95d7be6a9..2a09f8f67 100644 --- a/include/vr_flow.h +++ b/include/vr_flow.h @@ -231,7 +231,8 @@ struct vr_packet_node { uint32_t pl_inner_dst_ip; uint32_t pl_label; uint32_t pl_vif_idx; - uint32_t pl_flags; + uint16_t pl_flags; + int16_t pl_dscp; uint32_t pl_vrf; int32_t pl_vlan; }; @@ -297,7 +298,8 @@ struct vr_flow_queue { struct vr_dummy_flow_entry { vr_hentry_t fe_hentry; - uint8_t fe_hentry_packing[3]; + uint8_t fe_pack_hentry; + int16_t fe_qos_id; struct vr_flow fe_key; uint8_t fe_gen_id; uint16_t fe_tcp_flags; @@ -323,7 +325,8 @@ struct vr_dummy_flow_entry { /* do not change. any field positions as it might lead to incompatibility */ struct vr_flow_entry { vr_hentry_t fe_hentry; - uint8_t fe_hentry_packing[3]; + uint8_t fe_pack_hentry; + int16_t fe_qos_id; struct vr_flow fe_key; uint8_t fe_gen_id; uint16_t fe_tcp_flags; @@ -401,7 +404,7 @@ void *vr_flow_get_va(struct vrouter *, uint64_t); unsigned int vr_flow_table_size(struct vrouter *); -struct vr_flow_entry *vr_get_flow_entry(struct vrouter *, int); +struct vr_flow_entry *vr_flow_get_entry(struct vrouter *, int); flow_result_t vr_flow_lookup(struct vrouter *, struct vr_flow *, struct vr_packet *, struct vr_forwarding_md *); @@ -412,8 +415,7 @@ flow_result_t vr_inet6_flow_lookup(struct vrouter *, struct vr_packet *, int vr_inet6_form_flow(struct vrouter *, unsigned short, struct vr_packet *, uint16_t, struct vr_ip6 *, struct vr_flow *); -unsigned short -vr_inet_flow_nexthop(struct vr_packet *pkt, unsigned short vlan); +extern unsigned short vr_inet_flow_nexthop(struct vr_packet *, unsigned short); extern flow_result_t vr_inet_flow_nat(struct vr_flow_entry *, struct vr_packet *, struct vr_forwarding_md *); extern void vr_inet_fill_flow(struct vr_flow *, unsigned short, @@ -440,5 +442,7 @@ void vr_flow_fill_pnode(struct vr_packet_node *, struct vr_packet *, struct vr_forwarding_md *); fat_flow_port_mask_t vr_flow_fat_flow_lookup(struct vrouter *, struct vr_packet *, uint16_t, uint16_t, uint16_t); +extern int16_t vr_flow_get_qos(struct vrouter *, struct vr_packet *, + struct vr_forwarding_md *); #endif /* __VR_FLOW_H__ */ diff --git a/include/vr_interface.h b/include/vr_interface.h index 3c920fbf0..724d4fe2f 100644 --- a/include/vr_interface.h +++ b/include/vr_interface.h @@ -9,6 +9,7 @@ #include "vr_defs.h" #include "vr_types.h" #include "vr_htable.h" +#include "vr_qos.h" #include "vr_flow.h" /* @@ -262,6 +263,7 @@ struct vr_interface { unsigned char vif_name[VR_INTERFACE_NAME_LEN]; unsigned short vif_vrf_table_users; unsigned int vif_ip; + int16_t vif_qos_map_index; }; struct vr_interface_settings { diff --git a/include/vr_message.h b/include/vr_message.h index 911bb9333..9880bfd2a 100644 --- a/include/vr_message.h +++ b/include/vr_message.h @@ -30,6 +30,8 @@ #define VR_VROUTER_OPS_OBJECT_ID 12 #define VR_FLOW_INFO_OBJECT_ID 13 #define VR_MEM_STATS_OBJECT_ID 14 +#define VR_QOS_MAP_OBJECT_ID 15 +#define VR_FC_MAP_OBJECT_ID 16 #define VR_MESSAGE_PAGE_SIZE (4096 - 128) diff --git a/include/vr_mpls.h b/include/vr_mpls.h index 197bad4f7..90c3cd6f7 100644 --- a/include/vr_mpls.h +++ b/include/vr_mpls.h @@ -7,6 +7,7 @@ #define __VR_MPLS_H__ #define VR_MPLS_LABEL_SHIFT 12 +#define VR_MPLS_EXP_QOS_SHIFT 9 #define VR_MPLS_HDR_LEN 4 #define VR_MAX_UCAST_LABELS 1024 #define VR_DEF_LABELS 5120 diff --git a/include/vr_packet.h b/include/vr_packet.h index b914e5533..fd1c014ac 100644 --- a/include/vr_packet.h +++ b/include/vr_packet.h @@ -7,6 +7,7 @@ #define __VR_PACKET_H__ #include "vr_defs.h" +#include "vr_qos.h" #include "vr_flow.h" #include "vrouter.h" @@ -76,6 +77,7 @@ #define VP_FLAG_GSO (1 << 7) /* Diagnostic packet */ #define VP_FLAG_DIAG (1 << 8) +#define VP_FLAG_GROED (1 << 9) /* * possible 256 values of what a packet can be. currently, this value is @@ -250,6 +252,9 @@ struct vr_packet { unsigned char vp_cpu; unsigned char vp_type; unsigned char vp_ttl; + unsigned char vp_queue; + unsigned char vp_priority:4, + vp_notused:4; }; @@ -364,6 +369,62 @@ struct vr_ip { unsigned int ip_daddr; } __attribute__((packed)); +static inline void +vr_incremental_diff(unsigned int oldval, unsigned int newval, + unsigned int *diff) +{ + unsigned int tmp; + + tmp = ~oldval + newval; + if (tmp < newval) + tmp += 1; + + *diff += tmp; + if (*diff < tmp) + *diff += 1; + + return; +} + +static inline void +vr_ip_incremental_csum(struct vr_ip *ip, unsigned int diff) +{ + unsigned int csum; + + diff &= 0xffff; + csum = ~(ip->ip_csum) & 0xffff; + csum += diff; + csum = (csum >> 16) + (csum & 0xffff); + if (csum >> 16) + csum = (csum & 0xffff) + 1; + + ip->ip_csum = (~csum & 0xffff); + return; +} + +static inline uint8_t +vr_inet_get_tos(struct vr_ip *iph) +{ + return iph->ip_tos & 0x3F; +} + +static inline void +vr_inet_set_tos(struct vr_ip *iph, uint8_t tos) +{ + unsigned int diff = 0; + + if (iph->ip_tos == tos) + return; + + vr_incremental_diff(iph->ip_tos, tos, &diff); + diff <<= 8; + iph->ip_tos = tos; + vr_ip_incremental_csum(iph, diff); + + return; +} + + #define SOURCE_LINK_LAYER_ADDRESS_OPTION 1 #define TARGET_LINK_LAYER_ADDRESS_OPTION 2 @@ -420,6 +481,21 @@ struct vr_ip6 { #define VR_IP4_MAPPED_IP6_ZERO_BYTES 10 #define VR_IP4_MAPPED_IP6_ONE_BYTES 2 +static inline uint8_t +vr_inet6_get_tos(struct vr_ip6 *ip6h) +{ + return (((ip6h->ip6_priority_h << 4) | (ip6h->ip6_priority_l)) & 0x3F); +} + +static inline void +vr_inet6_set_tos(struct vr_ip6 *ip6h, uint8_t tos) +{ + ip6h->ip6_priority_h = (tos >> 4) & 0x3; + ip6h->ip6_priority_l = (tos & 0xF); + + return; +} + static inline void vr_inet6_generate_ip6(uint8_t *ip6, uint32_t ip) { @@ -610,22 +686,6 @@ vr_ip_transport_header_valid(struct vr_ip *iph) return true; } -static inline void -vr_incremental_diff(unsigned int oldval, unsigned int newval, - unsigned int *diff) -{ - unsigned int tmp; - - tmp = ~oldval + newval; - if (tmp < newval) - tmp += 1; - - *diff += tmp; - if (*diff < tmp) - *diff += 1; - - return; -} #define VR_TCP_FLAG_FIN 0x0001 #define VR_TCP_FLAG_SYN 0x0002 @@ -825,6 +885,8 @@ struct vr_forwarding_md { uint8_t fmd_to_me; uint8_t fmd_src; uint8_t fmd_flags; + int8_t fmd_dscp; + int8_t fmd_queue; }; static inline void @@ -841,6 +903,7 @@ vr_init_forwarding_md(struct vr_forwarding_md *fmd) fmd->fmd_to_me = 0; fmd->fmd_src = 0; fmd->fmd_flags = 0; + fmd->fmd_dscp = -1; return; } diff --git a/include/vr_qos.h b/include/vr_qos.h new file mode 100644 index 000000000..bc01da28d --- /dev/null +++ b/include/vr_qos.h @@ -0,0 +1,57 @@ +/* + * vr_qos.h -- + * + * Copyright (c) 2016, Juniper Networks, Inc. + * All rights reserved + */ +#ifndef __VR_QOS_H__ +#define __VR_QOS_H__ + +#define VR_DEF_QOS_MAP_ENTRIES 4096 +#define VR_DEF_FC_MAP_ENTRIES 256 +#define VR_DSCP_QOS_ENTRIES 64 +#define VR_MPLS_QOS_ENTRIES 8 +#define VR_DOTONEP_QOS_ENTRIES 8 +#define VR_QOS_MAP_ENTRY_SIZE (VR_DSCP_QOS_ENTRIES + \ + VR_MPLS_QOS_ENTRIES + \ + VR_DOTONEP_QOS_ENTRIES) + +/* + * We split the structure this way because flow structure has only + * 3 bytes of space between hash entry and key. Adding any other + * fields here should mean change in the location of the entry in + * the flow structure + */ +struct vr_forwarding_class_qos { + uint8_t vfcq_dscp; + uint8_t vfcq_mpls_qos:3, + vfcq_dotonep_qos:3, + vfcq_untrusted:1, + vfcq_valid:1; + uint8_t vfcq_queue_id; +} __attribute__((packed)); + +struct vr_forwarding_class { + uint8_t vfc_id; + struct vr_forwarding_class_qos vfc_qos; +} __attribute__((packed)); + +/* for easy access */ +#define vfc_dscp vfc_qos.vfcq_dscp +#define vfc_mpls_qos vfc_qos.vfcq_mpls_qos +#define vfc_dotonep_qos vfc_qos.vfcq_dotonep_qos +#define vfc_queue_id vfc_qos.vfcq_queue_id +#define vfc_untrusted vfc_qos.vfcq_untrusted +#define vfc_valid vfc_qos.vfcq_valid + +struct vrouter; +struct vr_forwarding_md; +struct vr_packet; + +extern int vr_qos_init(struct vrouter *); +extern void vr_qos_exit(struct vrouter *, bool); +struct vr_forwarding_class_qos *vr_qos_get_forwarding_class(struct vrouter *, + struct vr_packet *, struct vr_forwarding_md *); +extern unsigned int vr_qos_map_req_get_size(void *); + +#endif /* __VR_QOS_H__ */ diff --git a/include/vrouter.h b/include/vrouter.h index 9ab619758..a3926435b 100644 --- a/include/vrouter.h +++ b/include/vrouter.h @@ -12,6 +12,7 @@ extern "C" { #include "sandesh.h" #include "vr_types.h" +#include "vr_qos.h" #include "vr_flow.h" #include "vr_nexthop.h" #include "vr_route.h" @@ -102,6 +103,8 @@ enum vr_malloc_objects_t { VR_USOCK_IOVEC_OBJECT, VR_VROUTER_REQ_OBJECT, VR_BITMAP_OBJECT, + VR_QOS_MAP_OBJECT, + VR_FC_OBJECT, VR_VROUTER_MAX_OBJECT, }; @@ -294,6 +297,9 @@ struct vrouter { uint16_t vr_link_local_ports_size; unsigned char *vr_link_local_ports; + struct vr_forwarding_class **vr_qos_map; + struct vr_forwarding_class *vr_fc_table; + struct vr_interface *vr_agent_if; struct vr_interface *vr_host_if; struct vr_interface *vr_eth_if; diff --git a/linux/vr_host_interface.c b/linux/vr_host_interface.c index 8d836b985..c9a421b8f 100644 --- a/linux/vr_host_interface.c +++ b/linux/vr_host_interface.c @@ -194,6 +194,9 @@ linux_if_rx(struct vr_interface *vif, struct vr_packet *pkt) skb->len = pkt_len(pkt); skb_set_tail_pointer(skb, pkt_head_len(pkt)); + skb->queue_mapping = pkt->vp_queue; + skb->priority = pkt->vp_priority; + if (!dev) { vif_drop_pkt(vif, pkt, false); goto exit_rx; @@ -789,6 +792,8 @@ linux_if_tx(struct vr_interface *vif, struct vr_packet *pkt) } skb_reset_mac_header(skb); + skb->queue_mapping = pkt->vp_queue; + skb->priority = pkt->vp_priority; /* * Set the network header and trasport header of skb only if the type is @@ -915,6 +920,8 @@ linux_get_packet(struct sk_buff *skb, struct vr_interface *vif) pkt->vp_ttl = 64; pkt->vp_type = VP_TYPE_NULL; + pkt->vp_queue = 0; + pkt->vp_priority = 0; return pkt; @@ -2051,6 +2058,8 @@ pkt_gro_dev_rx_handler(struct sk_buff **pskb) if (!pkt) return RX_HANDLER_CONSUMED; + pkt->vp_flags |= VP_FLAG_GROED; + /* * since vif was not available when we did linux_get_packet, set vif * manually here diff --git a/linux/vrouter_mod.c b/linux/vrouter_mod.c index 9c9693ee2..618b06dca 100644 --- a/linux/vrouter_mod.c +++ b/linux/vrouter_mod.c @@ -676,7 +676,7 @@ lh_get_udp_src_port(struct vr_packet *pkt, struct vr_forwarding_md *fmd, } if (fmd && fmd->fmd_flow_index >= 0) { - fentry = vr_get_flow_entry(router, fmd->fmd_flow_index); + fentry = vr_flow_get_entry(router, fmd->fmd_flow_index); if (fentry) { lh_reset_skb_fields(pkt); return fentry->fe_udp_src_port; diff --git a/sandesh/vr.sandesh b/sandesh/vr.sandesh index 1b6989357..7b3d0180a 100644 --- a/sandesh/vr.sandesh +++ b/sandesh/vr.sandesh @@ -105,7 +105,8 @@ buffer sandesh vr_interface_req { 49: i32 vifr_bridge_idx; 50: i16 vifr_ovlan_id; 51: byte vifr_transport; - 52: list vifr_fat_flow_protocol_port; + 52: list vifr_fat_flow_protocol_port; + 53: i16 vifr_qos_map_index; } buffer sandesh vr_vxlan_req { @@ -188,6 +189,7 @@ buffer sandesh vr_flow_req { 35: u32 fr_flow_stats_oflow; 36: i32 fr_oflow_entries; 37: byte fr_gen_id; + 38: i16 fr_qos_id; } buffer sandesh vr_vrf_assign_req { @@ -332,6 +334,8 @@ buffer sandesh vr_mem_stats_req { 58: i64 vms_usock_iovec_object; 59: i64 vms_vrouter_req_object; 60: i64 vms_interface_fat_flow_config_object; + 61: i64 vms_qos_map_object; + 62: i64 vms_fc_object; } /* any new addition needs update to vr_util.c & flow.c */ @@ -388,3 +392,27 @@ buffer sandesh vr_drop_stats_req { 50: i64 vds_vlan_fwd_tx; 51: i64 vds_vlan_fwd_enq; } + +buffer sandesh vr_qos_map_req { + 1: sandesh_op h_op; + 2: u16 qmr_rid; + 3: u16 qmr_id; + 4: list qmr_dscp; + 5: list qmr_dscp_fc_id; + 6: list qmr_mpls_qos; + 7: list qmr_mpls_qos_fc_id; + 8: list qmr_dotonep; + 9: list qmr_dotonep_fc_id; + 10: i16 qmr_marker; +} + +buffer sandesh vr_fc_map_req { + 1: sandesh_op h_op; + 2: u16 fmr_rid; + 3: list fmr_id; + 4: list fmr_dscp; + 5: list fmr_mpls_qos; + 6: list fmr_dotonep; + 7: list fmr_queue_id; + 8: i16 fmr_marker; +} diff --git a/utils/SConscript b/utils/SConscript index 6face2eee..6c318069d 100644 --- a/utils/SConscript +++ b/utils/SConscript @@ -69,9 +69,12 @@ vrouter = env.Program(target = 'vrouter', source = vrouter_sources) vrmemstats_sources = ['vrmemstats.c'] vrmemstats = env.Program(target = 'vrmemstats', source = vrmemstats_sources) +qosmap_sources = ['qosmap.c'] +qosmap = env.Program(target = 'qosmap', source = qosmap_sources) + # to make sure that all are built when you do 'scons' @ the top level binaries = [vif, rt, nh, mirror, mpls, flow, vrfstats, dropstats, - vxlan, vrouter, vrmemstats] + vxlan, vrouter, vrmemstats, qosmap] scripts = ['vifdump'] env.Default(binaries) diff --git a/utils/flow.c b/utils/flow.c index 29ba5ec60..d84ace3e5 100644 --- a/utils/flow.c +++ b/utils/flow.c @@ -36,6 +36,7 @@ #endif #include "vr_types.h" +#include "vr_qos.h" #include "vr_flow.h" #include "vr_mirror.h" #include "vr_genetlink.h" @@ -1387,6 +1388,7 @@ flow_dump_table(struct flow_table *ft) if (fe->fe_ecmp_nh_index >= 0) printf("E:%d, ", fe->fe_ecmp_nh_index); + printf("QOS:%d, ", fe->fe_qos_id); printf("S(nh):%u, ", fe->fe_src_nh_index); printf(" Stats:%u/%u, ", fe->fe_stats.flow_packets, fe->fe_stats.flow_bytes); diff --git a/utils/nl_util.c b/utils/nl_util.c index f72fc5a1a..d4222baaa 100644 --- a/utils/nl_util.c +++ b/utils/nl_util.c @@ -48,6 +48,8 @@ extern void vr_vrf_stats_req_process(void *s_req) __attribute__((weak)); extern void vr_drop_stats_req_process(void *s_req) __attribute__((weak)); extern void vr_vxlan_req_process(void *s_req) __attribute__((weak)); extern void vr_mem_stats_req_process(void *s_req) __attribute__((weak)); +extern void vr_fc_map_req_process(void *s_req) __attribute__((weak)); +extern void vr_qos_map_req_process(void *s_req) __attribute__((weak)); void vrouter_ops_process(void *s_req) @@ -129,6 +131,18 @@ vr_mem_stats_req_process(void *s_req) return; } +void +vr_qos_map_req_process(void *s_req) +{ + return; +} + +void +vr_fc_map_req_process(void *s_req) +{ + return; +} + struct nl_response * nl_parse_gen_ctrl(struct nl_client *cl) { diff --git a/utils/qosmap.c b/utils/qosmap.c new file mode 100644 index 000000000..97158b468 --- /dev/null +++ b/utils/qosmap.c @@ -0,0 +1,366 @@ +/* + * qosmap.c -- utility to set and get qos mappings + * + * Copyright (c) 2016, Juniper Networks, Inc. + * All rights reserved + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#if defined(__linux__) +#include + +#include +#include +#include +#endif + +#include +#if defined(__linux__) +#include +#endif + +#include "vr_types.h" +#include "vr_qos.h" +#include "vr_flow.h" +#include "vr_mirror.h" +#include "vr_genetlink.h" +#include "nl_util.h" +#include "vr_os.h" +#include "ini_parser.h" +#include "vr_packet.h" + +static bool dump_pending = false; +static int marker = -1; + +unsigned int help_set, dump_fc_set, dump_qos_set; +unsigned int get_fc_set, set_fc_set, fc_set; +unsigned int get_qos_set, set_qos_set, delete_qos_set; +unsigned int dscp_set, mpls_qos_set, dotonep_set, queue_set; + +uint8_t dotonep, dscp, mpls_qos, fc, queue; +unsigned int qos_index; + +struct nl_client *cl; + +void +vr_fc_map_req_process(void *s) +{ + unsigned int i; + vr_fc_map_req *req = (vr_fc_map_req *)s; + + if (marker == -1) { + printf("Forwarding Class Map %d\n", req->fmr_rid); + printf(" FC DSCP EXP .1p Queue\n"); + } + + for (i = 0; i < req->fmr_id_size; i++) { + printf("%3u %8u %3u %3u %8u\n", + req->fmr_id[i], req->fmr_dscp[i], req->fmr_mpls_qos[i], + req->fmr_dotonep[i], req->fmr_queue_id[i]); + } + + if (i > 0) { + marker = (unsigned int)(req->fmr_id[i - 1]); + } + + return; +} + +void +vr_qos_map_req_process(void *s) +{ + unsigned int i; + vr_qos_map_req *req = (vr_qos_map_req *)s; + + printf("QOS Map %d/%d\n", req->qmr_rid, req->qmr_id); + if (req->qmr_dscp_size) { + printf(" DSCP FC\n"); + for (i = 0; i < req->qmr_dscp_size; i++) { + if (req->qmr_dscp_fc_id[i]) + printf("%8u %8u\n", req->qmr_dscp[i], + req->qmr_dscp_fc_id[i]); + } + printf("\n"); + } + + if (req->qmr_mpls_qos_size) { + printf(" EXP FC\n"); + for (i = 0; i < req->qmr_mpls_qos_size; i++) { + if (req->qmr_mpls_qos_fc_id[i]) + printf("%8u %8u\n", req->qmr_mpls_qos[i], + req->qmr_mpls_qos_fc_id[i]); + } + printf("\n"); + } + + if (req->qmr_dotonep_size) { + printf(" DOTONEP FC\n"); + for (i = 0; i < req->qmr_dotonep_size; i++) { + if (req->qmr_dotonep_fc_id[i]) + printf("%8u %8u\n", req->qmr_dotonep[i], + req->qmr_dotonep_fc_id[i]); + } + printf("\n"); + } + + printf("\n"); + marker = req->qmr_id; + return; +} + +void +vr_response_process(void *s) +{ + vr_response_common_process((vr_response *)s, &dump_pending); + return; +} + +static int +qos_map_op(void) +{ + int ret; + unsigned int num_dscp, num_mpls_qos, num_dotonep; + bool dump = false; + +op_retry: + num_dscp = num_mpls_qos = num_dotonep = 0; + + if (get_fc_set) { + ret = vr_send_fc_map_get(cl, 0, qos_index); + } else if (set_fc_set) { + ret = vr_send_fc_map_add(cl, 0, (int16_t *)&qos_index, 1, + &dscp, &mpls_qos, &dotonep, &queue); + } else if (dump_fc_set) { + dump = true; + ret = vr_send_fc_map_dump(cl, 0, marker); + } else if (get_qos_set) { + ret = vr_send_qos_map_get(cl, 0, qos_index); + } else if (set_qos_set) { + if (dscp_set) + num_dscp = 1; + if (mpls_qos_set) + num_mpls_qos = 1; + if (dotonep_set) + num_dotonep = 1; + + ret = vr_send_qos_map_add(cl, 0, qos_index, + &dscp, num_dscp, &fc, + &mpls_qos, num_mpls_qos, &fc, + &dotonep, num_dotonep, &fc); + } else if (dump_qos_set) { + ret = vr_send_qos_map_dump(cl, 0, marker); + dump = true; + } else if (delete_qos_set) { + ret = vr_send_qos_map_delete(cl, 0, qos_index); + } else { + ret = -EINVAL; + } + + + if (ret < 0) + return ret; + + ret = vr_recvmsg(cl, dump); + if (ret <= 0) + return ret; + + if (dump_pending) + goto op_retry; + + return ret; +} + +enum opt_qos_index { + DELETE_QOS_MAP_OPT_INDEX, + DUMP_FC_OPT_INDEX, + DUMP_QOS_MAP_OPT_INDEX, + DOTONEP_OPT_INDEX, + DSCP_OPT_INDEX, + MPLS_QOS_OPT_INDEX, + FC_OPT_INDEX, + GET_FC_OPT_INDEX, + GET_QOS_MAP_OPT_INDEX, + QUEUE_ID_OPT_INDEX, + SET_FC_OPT_INDEX, + SET_QOS_MAP_OPT_INDEX, + HELP_OPT_INDEX, + MAX_OPT_INDEX +}; + +static struct option long_options[] = { + [DELETE_QOS_MAP_OPT_INDEX] = {"delete-qos", required_argument, &delete_qos_set, 1}, + [DUMP_FC_OPT_INDEX] = {"dump-fc", no_argument, &dump_fc_set, 1}, + [DUMP_QOS_MAP_OPT_INDEX] = {"dump-qos", no_argument, &dump_qos_set, 1}, + [DOTONEP_OPT_INDEX] = {"dotonep", required_argument, &dotonep_set, 1}, + [DSCP_OPT_INDEX] = {"dscp", required_argument, &dscp_set, 1}, + [MPLS_QOS_OPT_INDEX] = {"mpls_qos", required_argument, &mpls_qos_set, 1}, + [FC_OPT_INDEX] = {"fc", required_argument, &fc_set, 1}, + [GET_FC_OPT_INDEX] = {"get-fc", required_argument, &get_fc_set, 1}, + [GET_QOS_MAP_OPT_INDEX] = {"get-qos", required_argument, &get_qos_set, 1}, + [QUEUE_ID_OPT_INDEX] = {"queue", required_argument, &queue_set, 1}, + [SET_FC_OPT_INDEX] = {"set-fc", required_argument, &set_fc_set, 1}, + [SET_QOS_MAP_OPT_INDEX] = {"set-qos", required_argument, &set_qos_set, 1}, + [HELP_OPT_INDEX] = {"help", no_argument, &help_set, 1}, + [MAX_OPT_INDEX] = { NULL, 0, 0, 0} +}; + + +static void +Usage(void) +{ + printf("qosmap --get-fc \n"); + printf(" --set-fc <--dscp | --mpls_qos | --dotonep | --queue> \n"); + printf(" --get-qos \n"); + printf(" --set-qos <--dscp | --mpls_qos | --dotonep> --fc \n"); + printf(" --dump-fc\n"); + printf(" --dump-qos\n"); + printf(" --delete-qos \n"); + + exit(EINVAL); + + return; +} + +static void +validate_options(void) +{ + unsigned int set = dotonep_set + mpls_qos_set + dscp_set + queue_set; + unsigned int op_set = get_fc_set + get_qos_set + set_fc_set + + set_qos_set + dump_fc_set + dump_qos_set + delete_qos_set; + + if (op_set != 1) { + goto exit_options; + } + + if (get_fc_set) { + if (fc_set || set) { + printf("Invalid arguments for --get-fc\n"); + goto exit_options; + } + } else if (get_qos_set) { + if (fc_set || set) { + printf("Invalid arguments to --get-qos\n"); + goto exit_options; + } + } else if (set_fc_set) { + if (fc_set || (set != 4)) { + printf("Invalid options to --set-fc\n"); + goto exit_options; + } + } else if (set_qos_set) { + if (set != 1 || !fc_set) { + printf("Invalid options to --set-qos\n"); + goto exit_options; + } + } else if (dump_fc_set || dump_qos_set || delete_qos_set) { + if (set) { + printf("Invalid options\n"); + goto exit_options; + } + } + + return; + +exit_options: + Usage(); + return; +} + +static void +parse_long_opts(int opt_index, char *opt_arg) +{ + errno = 0; + + switch (opt_index) { + case DOTONEP_OPT_INDEX: + dotonep = strtoul(opt_arg, NULL, 0); + break; + + case DSCP_OPT_INDEX: + dscp = strtoul(opt_arg, NULL, 0); + break; + + case DUMP_FC_OPT_INDEX: + case DUMP_QOS_MAP_OPT_INDEX: + break; + + case MPLS_QOS_OPT_INDEX: + mpls_qos = strtoul(opt_arg, NULL, 0); + break; + + case FC_OPT_INDEX: + fc = strtoul(opt_arg, NULL, 0); + break; + + case QUEUE_ID_OPT_INDEX: + queue = strtoul(opt_arg, NULL, 0); + break; + + case GET_QOS_MAP_OPT_INDEX: + case GET_FC_OPT_INDEX: + case SET_FC_OPT_INDEX: + case SET_QOS_MAP_OPT_INDEX: + case DELETE_QOS_MAP_OPT_INDEX: + qos_index = strtoul(opt_arg, NULL, 0); + break; + + case HELP_OPT_INDEX: + default: + Usage(); + break; + } + + if (errno) { + perror("parse_long_opts"); + Usage(); + } + + return; +} + + +int +main(int argc, char *argv[]) +{ + char opt; + int ret, option_index; + + while ((opt = getopt_long(argc, argv, "", long_options, + &option_index)) >= 0) { + switch (opt) { + case 0: + parse_long_opts(option_index, optarg); + break; + + default: + Usage(); + } + } + + validate_options(); + + cl = vr_get_nl_client(VR_NETLINK_PROTO_DEFAULT); + if (!cl) + exit(1); + + ret = qos_map_op(); + if (ret) { + return ret; + } + + return 0; +} diff --git a/utils/vif.c b/utils/vif.c index f2c3f51b6..c93d79ebd 100644 --- a/utils/vif.c +++ b/utils/vif.c @@ -470,9 +470,9 @@ list_get_print(vr_interface_req *req) vr_get_if_type_string(req->vifr_type), MAC_VALUE((uint8_t *)req->vifr_mac), req->vifr_ip); vr_interface_print_head_space(); - printf("Vrf:%d Flags:%s MTU:%d Ref:%d\n", req->vifr_vrf, + printf("Vrf:%d Flags:%s MTU:%d QOS:%d Ref:%d\n", req->vifr_vrf, req->vifr_flags ? vr_if_flags(req->vifr_flags) : "NULL" , - req->vifr_mtu, req->vifr_ref_cnt); + req->vifr_mtu, req->vifr_qos_map_index, req->vifr_ref_cnt); if (platform == DPDK_PLATFORM) { vr_interface_pbem_counters_print("RX device", print_zero, diff --git a/utils/vr_util.c b/utils/vr_util.c index c32981f82..0372b9da5 100644 --- a/utils/vr_util.c +++ b/utils/vr_util.c @@ -1535,3 +1535,154 @@ vr_send_vxlan_add(struct nl_client *cl, unsigned int router_id, return vr_sendmsg(cl, &req, "vr_vxlan_req"); } +int +vr_send_fc_map_get(struct nl_client *cl, unsigned int router_id, + uint8_t fc_map_id) +{ + vr_fc_map_req req; + int16_t id = fc_map_id; + + memset(&req, 0, sizeof(req)); + req.h_op = SANDESH_OP_GET; + req.fmr_rid = router_id; + req.fmr_id = &id; + req.fmr_id_size = 1; + + return vr_sendmsg(cl, &req, "vr_fc_map_req"); +} + +int +vr_send_fc_map_dump(struct nl_client *cl, unsigned int router_id, + int marker) +{ + vr_fc_map_req req; + + memset(&req, 0, sizeof(req)); + req.h_op = SANDESH_OP_DUMP; + req.fmr_rid = router_id; + req.fmr_marker = marker; + + return vr_sendmsg(cl, &req, "vr_fc_map_req"); +} + +int +vr_send_fc_map_delete(struct nl_client *cl, unsigned int router_id, + uint8_t fc_id) +{ + vr_fc_map_req req; + int16_t id = fc_id; + + memset(&req, 0, sizeof(req)); + req.h_op = SANDESH_OP_DELETE; + req.fmr_rid = router_id; + req.fmr_id = &id; + req.fmr_id_size = 1; + + return vr_sendmsg(cl, &req, "vr_fc_map_req"); +} + +int +vr_send_fc_map_add(struct nl_client *cl, unsigned int router_id, + int16_t *fc_id, uint8_t fc_id_size, + uint8_t *dscp, uint8_t *mpls_qos, uint8_t *dotonep, uint8_t *queue) +{ + vr_fc_map_req req; + + memset(&req, 0, sizeof(req)); + req.fmr_rid = router_id; + + req.fmr_id = fc_id; + req.fmr_id_size = fc_id_size; + req.fmr_dscp = dscp; + req.fmr_dscp_size = fc_id_size; + req.fmr_mpls_qos = mpls_qos; + req.fmr_mpls_qos_size = fc_id_size; + req.fmr_dotonep = dotonep; + req.fmr_dotonep_size = fc_id_size; + req.fmr_queue_id = queue; + req.fmr_queue_id_size = fc_id_size; + + return vr_sendmsg(cl, &req, "vr_fc_map_req"); +} + +int +vr_send_qos_map_get(struct nl_client *cl, unsigned int router_id, + unsigned int qos_map_id) +{ + vr_qos_map_req req; + + memset(&req, 0, sizeof(req)); + req.h_op = SANDESH_OP_GET; + req.qmr_rid = router_id; + req.qmr_id = qos_map_id; + + return vr_sendmsg(cl, &req, "vr_qos_map_req"); +} + + +int +vr_send_qos_map_dump(struct nl_client *cl, unsigned int router_id, + int marker) +{ + vr_qos_map_req req; + + memset(&req, 0, sizeof(req)); + req.h_op = SANDESH_OP_DUMP; + req.qmr_rid = router_id; + req.qmr_marker = marker; + + return vr_sendmsg(cl, &req, "vr_qos_map_req"); +} + +int +vr_send_qos_map_delete(struct nl_client *cl, unsigned int router_id, + unsigned int qos_map_id) +{ + vr_qos_map_req req; + + memset(&req, 0, sizeof(req)); + req.h_op = SANDESH_OP_DELETE; + req.qmr_rid = router_id; + req.qmr_id = qos_map_id; + + return vr_sendmsg(cl, &req, "vr_qos_map_req"); +} + +int +vr_send_qos_map_add(struct nl_client *cl, unsigned int router_id, + unsigned int qos_id, + uint8_t *dscp, uint8_t num_dscp, uint8_t *dscp_fc_id, + uint8_t *mpls_qos, uint8_t num_mpls_qos, uint8_t *mpls_qos_fc_id, + uint8_t *dotonep, uint8_t num_dotonep, uint8_t *dotonep_fc_id) +{ + vr_qos_map_req req; + + memset(&req, 0, sizeof(req)); + req.h_op = SANDESH_OP_ADD; + req.qmr_rid = router_id; + req.qmr_id = qos_id; + + if (num_dscp) { + req.qmr_dscp = dscp; + req.qmr_dscp_size = num_dscp; + req.qmr_dscp_fc_id = dscp_fc_id; + req.qmr_dscp_fc_id_size = num_dscp; + } + + if (num_mpls_qos) { + req.qmr_mpls_qos = mpls_qos; + req.qmr_mpls_qos_size = num_mpls_qos; + req.qmr_mpls_qos_fc_id = mpls_qos_fc_id; + req.qmr_mpls_qos_fc_id_size = num_mpls_qos; + } + + if (num_dotonep) { + req.qmr_dotonep = dotonep; + req.qmr_dotonep_size = num_dotonep; + req.qmr_dotonep_fc_id = dotonep_fc_id; + req.qmr_dotonep_fc_id_size = num_dotonep; + } + + return vr_sendmsg(cl, &req, "vr_qos_map_req"); +} + diff --git a/utils/vrmemstats.c b/utils/vrmemstats.c index ed7a8d6a8..40efdeb98 100644 --- a/utils/vrmemstats.c +++ b/utils/vrmemstats.c @@ -149,6 +149,10 @@ vr_mem_stats_req_process(void *s_req) stats->vms_usock_iovec_object); printf("Vrouter Request %" PRIu64 "\n", stats->vms_vrouter_req_object); + printf("QOS Map Objects %" PRIu64 "\n", + stats->vms_qos_map_object); + printf("Forwarding Class Objects %" PRIu64 "\n", + stats->vms_fc_object); return; } diff --git a/utils/vtest/sandesh_gen.c b/utils/vtest/sandesh_gen.c index 5e69c899e..06609da58 100644 --- a/utils/vtest/sandesh_gen.c +++ b/utils/vtest/sandesh_gen.c @@ -448,7 +448,8 @@ gen(FILE *fp) gen_write(fp_expect, nesting + 4, "strtoul(node->children->content, NULL, 0)"); gen_write(fp_expect, 0, ");\n"); - } else if (!strncmp(type, "i16", strlen("i16"))) { + } else if ((!strncmp(type, "i16", strlen("i16"))) || + (!strncmp(type, "u16", strlen("u16")))) { gen_write(ofp, 0, "strtoul(node->children->content, NULL, 0);\n"); gen_write(fp_expect, 0, "result = vt_gen_short_compare(");