IPv4数据包处理

  • IPv4协议pkt_type注册

    • ipv4_init时调用netif_register_pkt注册
    static struct pkt_type ip4_pkt_type = {
        //.type       = rte_cpu_to_be_16(ETHER_TYPE_IPv4),
        .func       = ipv4_rcv,
        .port       = NULL,
    };
    
    int ipv4_init(void)
    {
        int err, i;
    
        ip4_idents = rte_malloc(NULL, IP4_IDENTS_SZ * sizeof(*ip4_idents),
                                RTE_CACHE_LINE_SIZE);
        if (!ip4_idents)
            return EDPVS_NOMEM;
        ip4_id_hashrnd = (uint32_t)random();
        for (i = 0; i < IP4_IDENTS_SZ; i++)
            rte_atomic32_set(&ip4_idents[i], (uint32_t)random());
    
        rte_spinlock_init(&inet_prot_lock);
        rte_spinlock_lock(&inet_prot_lock);
        for (i = 0; i < NELEMS(inet_prots); i++)
            inet_prots[i] = NULL;
        rte_spinlock_unlock(&inet_prot_lock);
    
    #ifdef CONFIG_DPVS_IPV4_STATS
        rte_spinlock_init(&ip4_stats_lock);
    #endif
    
        if ((err = ipv4_frag_init()) != EDPVS_OK)
            return err;
    
        ip4_pkt_type.type = htons(ETHER_TYPE_IPv4);
        if ((err = netif_register_pkt(&ip4_pkt_type)) != EDPVS_OK) {
            ipv4_frag_term();
            return err;
        }
    
        return EDPVS_OK;
    }
    
  • ipv4_rcv

    • IPv4三层入口处理函数
    • 此时mbuf->data_off已经指向ipv4_hdr起始地址
    static int ipv4_rcv(struct rte_mbuf *mbuf, struct netif_port *port)
    {
        struct ipv4_hdr *iph;
        uint16_t hlen, len;
        eth_type_t etype = mbuf->packet_type; /* FIXME: use other field ? */
        assert(mbuf);
        //二层包类型不是传递至本机数据报,或者net_device设备不存在,释放数据包
        if (unlikely(etype == ETH_PKT_OTHERHOST || !port)) {
            rte_pktmbuf_free(mbuf);
            return EDPVS_DROP;
        }
        //更新统计数据
        IP4_UPD_PO_STATS(in, mbuf->pkt_len);
        iftraf_pkt_in(AF_INET, mbuf, port);
        //数据报长度校验
        if (mbuf_may_pull(mbuf, sizeof(struct ipv4_hdr)) != 0)
            goto inhdr_error;
        //获取ipv4包头
        iph = ip4_hdr(mbuf);
        //获取ipv4包头总长度,包括ip选项
        hlen = ip4_hdrlen(mbuf);
        //ip数据包有效性验证,version是ipv4,并且总长度不能小于20字节
        if (((iph->version_ihl) >> 4) != 4 || hlen < sizeof(struct ipv4_hdr))
            goto inhdr_error;
        //ip数据包长度验证
        if (mbuf_may_pull(mbuf, hlen) != 0)
            goto inhdr_error;
        //checksum验证
        if (unlikely(!(port->flag & NETIF_PORT_FLAG_RX_IP_CSUM_OFFLOAD))) {
            if (unlikely(rte_raw_cksum(iph, hlen) != 0xFFFF))
                goto csum_error;
        }
        //获取ip数据报总长度
        len = ntohs(iph->total_length);
        //如果mbuf的长度小于ipv4数据报总长度,则数据包可能被截断了,终止处理
        if (mbuf->pkt_len < len) {
            IP4_INC_STATS(intruncatedpkts);
            goto drop;
        } else if (len < hlen){
            //如果数据报总长度小于IPv4数据包头部长度,出错
            goto inhdr_error;
        }
    
        /* trim padding if needed */
        //如果mbuf总长度大于ip数据报长度,则需要截断后面补充字节,Ethernet中最小帧长度为68,如果不足的话会在后面补充一些数据
        if (mbuf->pkt_len > len) {
            if (rte_pktmbuf_trim(mbuf, mbuf->pkt_len - len) != 0) {
                IP4_INC_STATS(indiscards);
                goto drop;
            }
        }
        mbuf->userdata = NULL;
        //设置mbuf L3层长度
        mbuf->l3_len = hlen;
    
    #ifdef CONFIG_DPVS_IP_HEADER_DEBUG
        ip4_show_hdr(__func__, mbuf);
    #endif
        /**
          * 如果L4层协议为OSPF,传递至协议栈处理
          * OSPF(Open Shortest Path First开放式最短路径优先)是一个内部网关协议(Interior Gateway Protocol,简称IGP),
          * 用于在单一自治系统(autonomous system,AS)内决策路由。是对链路状态路由协议的一种实现,隶属内部网关协议(IGP),
          * 故运作于自治系统内部
          */
        if (unlikely(iph->next_proto_id == IPPROTO_OSPF))
            return EDPVS_KNICONTINUE;
        //最后调用 INET_HOOK(INET_HOOK_PRE_ROUTING, mbuf, port, NULL, ipv4_rcv_fin) 先调用 INET_HOOK_PRE_ROUTING 这个钩子所
        //注册的回调,然后根据返回值判断是否走 ipv4_rcv_fin,不同转发模式行为是不同的
        return INET_HOOK(AF_INET, INET_HOOK_PRE_ROUTING,
                         mbuf, port, NULL, ipv4_rcv_fin);
    
    csum_error:
        IP4_INC_STATS(csumerrors);
    inhdr_error:
        IP4_INC_STATS(inhdrerrors);
    drop:
        rte_pktmbuf_free(mbuf);
        return EDPVS_INVPKT;
    }
    
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值