From patchwork Mon Feb 22 19:40:15 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "svc.eng.git-mail" X-Patchwork-Id: 1443278 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.133; helo=hemlock.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=nutanix.com header.i=@nutanix.com header.a=rsa-sha256 header.s=proofpoint20171006 header.b=dp1CVu7P; dkim-atps=neutral Received: from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DksxV6gH6z9sCD for ; Tue, 23 Feb 2021 06:41:18 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 5B4A2870C6; Mon, 22 Feb 2021 19:41:17 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from hemlock.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id EuFFjAyLDSw5; Mon, 22 Feb 2021 19:41:15 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by hemlock.osuosl.org (Postfix) with ESMTP id 5B9D286F8C; Mon, 22 Feb 2021 19:41:15 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 47F0EC000A; Mon, 22 Feb 2021 19:41:15 +0000 (UTC) X-Original-To: ovs-dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138]) by lists.linuxfoundation.org (Postfix) with ESMTP id 93429C0001 for ; Mon, 22 Feb 2021 19:41:13 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 8DC6883187 for ; Mon, 22 Feb 2021 19:41:13 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id mSVmjp9pX5FK for ; Mon, 22 Feb 2021 19:41:10 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from mx0a-002c1b01.pphosted.com (mx0a-002c1b01.pphosted.com [148.163.151.68]) by smtp1.osuosl.org (Postfix) with ESMTPS id DEC4C82EA1 for ; Mon, 22 Feb 2021 19:41:10 +0000 (UTC) Received: from pps.filterd (m0127838.ppops.net [127.0.0.1]) by mx0a-002c1b01.pphosted.com (8.16.0.43/8.16.0.43) with SMTP id 11MJdrH3008858 for ; Mon, 22 Feb 2021 11:41:10 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nutanix.com; h=from : to : cc : subject : date : message-id : content-transfer-encoding : content-type : mime-version; s=proofpoint20171006; bh=yCjSt86Dhhdu/eogp3VsvofUin/SBphEPki2qIKrUnE=; b=dp1CVu7Pj/SISPfuxD1GJrQI8b0agfRyXPETltyC+4DTrC4IsHDTrE+qFQ+1isIJ5cnM MWFz4aM3iHlo60ZD5hrshLLBBYAuroDcrlxTRxtQL1zXqzq9SBjPKkZR4JWbd39pcWGS zSiz4xIAgsJYPizb4eA5unb0o7tep/ETVf82RrHLi/ShoyxrMM4ctzOCTFZwS5YFL8MK vZeAOY4l9PF2GCnTRgx/FOJmScN2MEFbLkoaMWE8z5s1MtEOI6kMZ1YoGGDeQd/SmU3Z 4t87dJ3keLSzFraTzfIXXYRvva1HLvL+IWBlOsMD13fL410BewIcqLWM/H7QR2ndsqbw RA== Received: from nam12-bn8-obe.outbound.protection.outlook.com (mail-bn8nam12lp2172.outbound.protection.outlook.com [104.47.55.172]) by mx0a-002c1b01.pphosted.com with ESMTP id 36u2v5467p-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Mon, 22 Feb 2021 11:41:09 -0800 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=MoXBKoSP12Od4QrJtwf0bBdaGlfHnUZ7Xftsyoyotz8Z0fLoLObDX8r9zMPlJFejByExD6O5bpb8TFuzFsGFi5sc9fSeZJEVsr+AqvnShkvEN2KVEqSILPHoz8qulv1D64mRyT3kZeENWU3/vSz6vbW6KnFtfgIvw4j0j9ENpvVYJ0nCOHQInnogKQQ3LnHITwYStmGtWzDzkwy1VGdEiYHtlD/ME/QoyXKwdhBevlJMuLAjw4AGY8m3ldOUAeGGz8kCFfTXTvCq376ufzcjoZ0ZGOQskghs5HGw4pr9DJIekLN5nhkURBzB7by0dGopXF3tYcxaSiZFhw0E9HVTSw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=yCjSt86Dhhdu/eogp3VsvofUin/SBphEPki2qIKrUnE=; b=LY7L7njl2Qxwfv8YaAeUDHyhQm4igvyF/dAK2xTQJoIyE0n09SC3mq8ExfvSCSg9VAMaFb1fNlKQTQmYskFsOMQwmqUcgVGPYIxXpslFMdKMncnGdb7NvU8aYuabZLYXggId+WFvCB4iqklPRP+MDJFgAguf4PWGtYR/vnC9CswqqEDJ4TcLg2Tn8UvbXbhpQ1mT2VDqyUSxpIrGv1Zs+AO/Hkqe3GyG2plUKkOhW8WhWLDTybieuItYYydTGBh5706zXGdPFHKIIO9l2IhOJiB4U64C5W36oRjTmyiu54/wsxtSieoCL/sb7e9EqtJeHsvrG2FdRmKWy8CXye2/+A== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nutanix.com; dmarc=pass action=none header.from=nutanix.com; dkim=pass header.d=nutanix.com; arc=none Authentication-Results: openvswitch.org; dkim=none (message not signed) header.d=none;openvswitch.org; dmarc=none action=none header.from=nutanix.com; Received: from DM6PR02MB6394.namprd02.prod.outlook.com (2603:10b6:5:1d1::33) by DM5PR02MB2763.namprd02.prod.outlook.com (2603:10b6:3:10f::11) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3868.27; Mon, 22 Feb 2021 19:41:07 +0000 Received: from DM6PR02MB6394.namprd02.prod.outlook.com ([fe80::17b:1d09:d879:30e9]) by DM6PR02MB6394.namprd02.prod.outlook.com ([fe80::17b:1d09:d879:30e9%7]) with mapi id 15.20.3868.032; Mon, 22 Feb 2021 19:41:07 +0000 From: svc.eng.git-mail@nutanix.com To: ovs-dev@openvswitch.org Date: Mon, 22 Feb 2021 19:40:15 +0000 Message-Id: <20210222194015.95508-1-svc.eng.git-mail@nutanix.com> X-Mailer: git-send-email 2.22.3 X-Originating-IP: [192.146.154.240] X-ClientProxiedBy: BYAPR02CA0035.namprd02.prod.outlook.com (2603:10b6:a02:ee::48) To DM6PR02MB6394.namprd02.prod.outlook.com (2603:10b6:5:1d1::33) MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 Received: from karthik-c.ubvm.nutanix.com (192.146.154.240) by BYAPR02CA0035.namprd02.prod.outlook.com (2603:10b6:a02:ee::48) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3868.27 via Frontend Transport; Mon, 22 Feb 2021 19:41:06 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: b72d7693-c5a4-4891-5ffb-08d8d769cc10 X-MS-TrafficTypeDiagnostic: DM5PR02MB2763: X-MS-Exchange-Transport-Forked: True X-Microsoft-Antispam-PRVS: x-proofpoint-crosstenant: true X-MS-Oob-TLC-OOBClassifiers: OLM:2582; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: htlrl3to9rauiC+BbPXIipb4KCYJdxjOZTfX7HGbUshyjbusdn0rYA9nL3X4a/+fbAMSC41WoX+p1aI+BVMK7LHpYCiTmLmKLJ193Z8TIxQzVRor1PMoViV2Hr7JSbieuEOOxBz3FWBkshS+3RGCEYG6dorpBdKIslYgRXe7gtC30quT9elz+ZlYGrEpWkoNHihgnbMYnLZl1ycqGLW68KkmXnzsiQgbPqcWk8Cp0F+/Z+Hn2lwpaKARBj+/Qnbe6nd/yHHZWXZGdLJfKvlBbrcy7diHJBAEXNnbdW16a1eUMo5Mfwfvqg2OEmBpmEt9cl6Evd1U4T/CD+8eMiKbFcSO+AAUHON7z15oYGEq3i9DsLIMavUVUaaKsRORrEq/zPg8FJOZQYA+7cmp6qO+PrD4wdisoaqCHmxvTVBmcDDpTi48y1mCjfMgKBsL9hWjIfMIBprhHzM/JjpQWgO2lTb1B+/antRdesiK8vtchdZnsy0uYpnlQXy9oqshZgQ//6clfH6gbdzsWnA7kWZibw== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:DM6PR02MB6394.namprd02.prod.outlook.com; PTR:; CAT:NONE; SFS:(346002)(366004)(376002)(136003)(39860400002)(396003)(1076003)(478600001)(5660300002)(86362001)(2906002)(8936002)(2616005)(66574015)(107886003)(8676002)(7696005)(956004)(83380400001)(6666004)(16526019)(52116002)(4326008)(103116003)(66946007)(30864003)(66556008)(26005)(6916009)(66476007)(186003)(9686003)(6486002)(36756003)(316002); DIR:OUT; SFP:1102; X-MS-Exchange-AntiSpam-MessageData: zimKVLonVNP9XQnbRaLn2S7NjwBthp2v4HRpX6u/SfZFFVN8wP47s8MDDXwIAVZv+LyqvlSlq2LFUNqjkUHNhOYLx8wpGkPzqRodzdSOTbbSzzL39G18OFc/b6wyV1wjPwwP68OOobmvO+tDbkyZF6kS7/5pDNuZTB7HzlsxPc5MNRXGEAaT3TyGsAuNJBw0kM+hvm/U7sRFwR3iXsptgZtRqCrfb1XubkrSsZA5tPcqtcDiPdFPQ5NcaCUFV39M8xhUSjHlYE0eh6tCvYGdSZ7O48T61dZRbPCDQhCzQ2LxHxTniD8smw+oWQGd7kjyLUMJBWEG5iKSc+C5Jz24VULSJldnOoznFdK6wN6mhgjiH7thvgAlA0/UmJicdSD/5PFAPXZuefYebPuho3qE8/w0nhlLPiy6Jl+HjHbixtbTOGQzX+oO7bGkfWyb0RoQFOvLFlYmlI9h/iykCbjPRdrTJg8yRSGY6FLSGeJIsElgIXwoPLYIiBU9fY9uY9hWUvOYqOW/ePtja1YVbuwHEnWnmN4CltXGlWyqDDu5kZu72SoGMX7unPnWaVk7PC8vr1A+bg6r5gBzC+HjSnDEjU7zzTu14jkGvzx3dpIKwCmUzujZ8aA/bwmMN0uB8fDsyTeCDpSvjYcPqbRQRc5t3iqYyu2dRIo4YSu9mUlWMYzXvd++xFLd4hOSlUDF3hdAv+a0lRUB7yC4kYVquU7CGGmrNrnlzdtZssZn5yRrfs1JEEzOMS5O9QuoOrtYNCzX1P8URRRDflz0kjIJYHuFf4hhwQjsw5g8k04rtn4maklBvENwrEzQiJ6i2R7+C0T78H2Y8CwmwdwgrK6LshS9QHdT1shxflgeJjJIp+9jwrlITElF/g+Wcw+nnYL5zRlam/nX3+Q5prAMBMIVPGBk0lLzB8bbQMGSI9P42ZoBZE6wCrnPBCnXrV2C8jfosb4IyaOW2GYYZcOKZDYlz1SO0IZ4UKoM3602YTQnWFEAuywY0ntyZz2iW6z0chf/R3WUdIozHa5XPS1ljA54M/dTOFHonUKEYFF9BkSFqQWxKLaM3KbZ+BMaKpXqby/rVi4LWwP5wi37cX4pQ2KzkOTYo6/C/Nc6fbjCN4Aymmg6qepzFky30orxzTLbOljYPMas0vo+09Q/MFfG6OFzKeJiZczOMEsk66qma8MdZxrIa7RCRvVwaRwZ8srqIx3tEt4m+e+4toQIj+pBdXdpK6g06GuTl3uS02+ISCIy6MOEdeO2i3Y05pI+fer9IV8V655k2Q4/4evQcJHDUTAv4ScoYNdJX/HA+WbY9RzqjuNxiOChyCatr1TP33Lek7a4jpyF X-OriginatorOrg: nutanix.com X-MS-Exchange-CrossTenant-Network-Message-Id: b72d7693-c5a4-4891-5ffb-08d8d769cc10 X-MS-Exchange-CrossTenant-AuthSource: DM6PR02MB6394.namprd02.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 22 Feb 2021 19:41:07.0327 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: bb047546-786f-4de1-bd75-24e5b6f79043 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: Lq0srQzaBaN5/f+0Kunwgq9/hAmJlO9NMjAPvF7Tl0ZPSlz6IrWQdLZYzUukbGGx0u+VnJddlGzijeO8w2jZwR8mciWkruolRuIG5gsMaAQ= X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM5PR02MB2763 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.369, 18.0.761 definitions=2021-02-22_06:2021-02-22, 2021-02-22 signatures=0 X-Proofpoint-Spam-Reason: safe Cc: karthik-kc Subject: [ovs-dev] [PATCH ovn v1] Static Routes: Add ability to specify "discard" nexthop X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: karthik-kc Physical switches have the ability to specify "discard" or sometimes "NULL interface" as a nexthop for routes. This can be used to prevent routing loops in the network. Add a similar configuration for ovn where nexthop accepts the string "discard". When the nexthop is discard the action in the routing table will be to drop the packets. Signed-off-by: Karthik Chandrashekar --- northd/ovn-northd.c | 126 +++++++++++++++++++++++------------------- ovn-nb.xml | 4 +- tests/ovn-nbctl.at | 13 +++++ tests/ovn.at | 93 +++++++++++++++++++++++++++++++ utilities/ovn-nbctl.c | 50 ++++++++++++----- 5 files changed, 215 insertions(+), 71 deletions(-) diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index 39d798782..18d0e0b43 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -7749,6 +7749,7 @@ struct parsed_route { uint32_t hash; const struct nbrec_logical_router_static_route *route; bool ecmp_symmetric_reply; + bool is_discard_route; }; static uint32_t @@ -7768,20 +7769,23 @@ parsed_routes_add(struct ovs_list *routes, /* Verify that the next hop is an IP address with an all-ones mask. */ struct in6_addr nexthop; unsigned int plen; - if (!ip46_parse_cidr(route->nexthop, &nexthop, &plen)) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); - VLOG_WARN_RL(&rl, "bad 'nexthop' %s in static route" - UUID_FMT, route->nexthop, - UUID_ARGS(&route->header_.uuid)); - return NULL; - } - if ((IN6_IS_ADDR_V4MAPPED(&nexthop) && plen != 32) || - (!IN6_IS_ADDR_V4MAPPED(&nexthop) && plen != 128)) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); - VLOG_WARN_RL(&rl, "bad next hop mask %s in static route" - UUID_FMT, route->nexthop, - UUID_ARGS(&route->header_.uuid)); - return NULL; + bool is_discard_route = !strcmp(route->nexthop, "discard"); + if (!is_discard_route) { + if (!ip46_parse_cidr(route->nexthop, &nexthop, &plen)) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); + VLOG_WARN_RL(&rl, "bad 'nexthop' %s in static route" + UUID_FMT, route->nexthop, + UUID_ARGS(&route->header_.uuid)); + return NULL; + } + if ((IN6_IS_ADDR_V4MAPPED(&nexthop) && plen != 32) || + (!IN6_IS_ADDR_V4MAPPED(&nexthop) && plen != 128)) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); + VLOG_WARN_RL(&rl, "bad next hop mask %s in static route" + UUID_FMT, route->nexthop, + UUID_ARGS(&route->header_.uuid)); + return NULL; + } } /* Parse ip_prefix */ @@ -7795,13 +7799,15 @@ parsed_routes_add(struct ovs_list *routes, } /* Verify that ip_prefix and nexthop have same address familiy. */ - if (IN6_IS_ADDR_V4MAPPED(&prefix) != IN6_IS_ADDR_V4MAPPED(&nexthop)) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); - VLOG_WARN_RL(&rl, "Address family doesn't match between 'ip_prefix' %s" - " and 'nexthop' %s in static route"UUID_FMT, - route->ip_prefix, route->nexthop, - UUID_ARGS(&route->header_.uuid)); - return NULL; + if (!is_discard_route) { + if (IN6_IS_ADDR_V4MAPPED(&prefix) != IN6_IS_ADDR_V4MAPPED(&nexthop)) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); + VLOG_WARN_RL(&rl, "Address family doesn't match between 'ip_prefix' %s" + " and 'nexthop' %s in static route"UUID_FMT, + route->ip_prefix, route->nexthop, + UUID_ARGS(&route->header_.uuid)); + return NULL; + } } const struct nbrec_bfd *nb_bt = route->bfd; @@ -7832,6 +7838,7 @@ parsed_routes_add(struct ovs_list *routes, pr->route = route; pr->ecmp_symmetric_reply = smap_get_bool(&route->options, "ecmp_symmetric_reply", false); + pr->is_discard_route = is_discard_route; ovs_list_insert(routes, &pr->list_node); return pr; } @@ -8244,10 +8251,11 @@ build_ecmp_route_flow(struct hmap *lflows, struct ovn_datapath *od, } static void -add_route(struct hmap *lflows, const struct ovn_port *op, - const char *lrp_addr_s, const char *network_s, int plen, - const char *gateway, bool is_src_route, - const struct ovsdb_idl_row *stage_hint) +add_route(struct hmap *lflows, struct ovn_datapath *od, + const struct ovn_port *op, const char *lrp_addr_s, + const char *network_s, int plen, const char *gateway, + bool is_src_route, const struct ovsdb_idl_row *stage_hint, + bool is_discard_route) { bool is_ipv4 = strchr(network_s, '.') ? true : false; struct ds match = DS_EMPTY_INITIALIZER; @@ -8266,30 +8274,34 @@ add_route(struct hmap *lflows, const struct ovn_port *op, &match, &priority); struct ds common_actions = DS_EMPTY_INITIALIZER; - ds_put_format(&common_actions, REG_ECMP_GROUP_ID" = 0; %s = ", - is_ipv4 ? REG_NEXT_HOP_IPV4 : REG_NEXT_HOP_IPV6); - if (gateway) { - ds_put_cstr(&common_actions, gateway); - } else { - ds_put_format(&common_actions, "ip%s.dst", is_ipv4 ? "4" : "6"); - } - ds_put_format(&common_actions, "; " - "%s = %s; " - "eth.src = %s; " - "outport = %s; " - "flags.loopback = 1; " - "next;", - is_ipv4 ? REG_SRC_IPV4 : REG_SRC_IPV6, - lrp_addr_s, - op->lrp_networks.ea_s, - op->json_key); struct ds actions = DS_EMPTY_INITIALIZER; - ds_put_format(&actions, "ip.ttl--; %s", ds_cstr(&common_actions)); + if (is_discard_route) { + ds_put_format(&actions, "drop;"); + } else { + ds_put_format(&common_actions, REG_ECMP_GROUP_ID" = 0; %s = ", + is_ipv4 ? REG_NEXT_HOP_IPV4 : REG_NEXT_HOP_IPV6); + if (gateway) { + ds_put_cstr(&common_actions, gateway); + } else { + ds_put_format(&common_actions, "ip%s.dst", is_ipv4 ? "4" : "6"); + } + ds_put_format(&common_actions, "; " + "%s = %s; " + "eth.src = %s; " + "outport = %s; " + "flags.loopback = 1; " + "next;", + is_ipv4 ? REG_SRC_IPV4 : REG_SRC_IPV6, + lrp_addr_s, + op->lrp_networks.ea_s, + op->json_key); + ds_put_format(&actions, "ip.ttl--; %s", ds_cstr(&common_actions)); + } - ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_ROUTING, priority, + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_ROUTING, priority, ds_cstr(&match), ds_cstr(&actions), stage_hint); - if (op->has_bfd) { + if (op && op->has_bfd) { ds_put_format(&match, " && udp.dst == 3784"); ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_ROUTING, priority + 1, ds_cstr(&match), @@ -8311,16 +8323,18 @@ build_static_route_flow(struct hmap *lflows, struct ovn_datapath *od, const struct nbrec_logical_router_static_route *route = route_->route; /* Find the outgoing port. */ - if (!find_static_route_outport(od, ports, route, - IN6_IS_ADDR_V4MAPPED(&route_->prefix), - &lrp_addr_s, &out_port)) { - return; + if (!route_->is_discard_route) { + if (!find_static_route_outport(od, ports, route, + IN6_IS_ADDR_V4MAPPED(&route_->prefix), + &lrp_addr_s, &out_port)) { + return; + } } char *prefix_s = build_route_prefix_s(&route_->prefix, route_->plen); - add_route(lflows, out_port, lrp_addr_s, prefix_s, route_->plen, - route->nexthop, route_->is_src_route, - &route->header_); + add_route(lflows, route_->is_discard_route ? od : out_port->od, out_port, + lrp_addr_s, prefix_s, route_->plen, route->nexthop, + route_->is_src_route, &route->header_, route_->is_discard_route); free(prefix_s); } @@ -9386,17 +9400,17 @@ build_ip_routing_flows_for_lrouter_port( if (op->nbrp) { for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { - add_route(lflows, op, op->lrp_networks.ipv4_addrs[i].addr_s, + add_route(lflows, op->od, op, op->lrp_networks.ipv4_addrs[i].addr_s, op->lrp_networks.ipv4_addrs[i].network_s, op->lrp_networks.ipv4_addrs[i].plen, NULL, false, - &op->nbrp->header_); + &op->nbrp->header_, false); } for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { - add_route(lflows, op, op->lrp_networks.ipv6_addrs[i].addr_s, + add_route(lflows, op->od, op, op->lrp_networks.ipv6_addrs[i].addr_s, op->lrp_networks.ipv6_addrs[i].network_s, op->lrp_networks.ipv6_addrs[i].plen, NULL, false, - &op->nbrp->header_); + &op->nbrp->header_, false); } } } diff --git a/ovn-nb.xml b/ovn-nb.xml index a94918bb6..85efd70f2 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -2636,7 +2636,9 @@

Nexthop IP address for this route. Nexthop IP address should be the IP - address of a connected router port or the IP address of a logical port. + address of a connected router port or the IP address of a logical port + or can be set to "discard" for dropping packets which match the given + route.

diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at index 6d91aa4c5..f4b2a88c2 100644 --- a/tests/ovn-nbctl.at +++ b/tests/ovn-nbctl.at @@ -1467,18 +1467,26 @@ AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.0.111/24 11.0.0.1/24], [1], [], AT_CHECK([ovn-nbctl lr-route-add lr0 2001:0db8:1::/64 2001:0db8:0:f103::1/64], [1], [], [ovn-nbctl: bad IPv6 nexthop argument: 2001:0db8:0:f103::1/64 ]) +AT_CHECK([ovn-nbctl lr-route-add lr0 20.0.0.0/24 discard lp0], [1], [], + [ovn-nbctl: outport is not valid for discard routes. +]) AT_CHECK([ovn-nbctl --may-exist lr-route-add lr0 10.0.0.111/24 11.0.0.1]) AT_CHECK([ovn-nbctl --policy=src-ip lr-route-add lr0 9.16.1.0/24 11.0.0.1]) dnl Add a route with existed prefix but different policy (src-ip) AT_CHECK([ovn-nbctl --policy=src-ip lr-route-add lr0 10.0.0.0/24 11.0.0.2]) +AT_CHECK([ovn-nbctl lr-route-add lr0 20.0.0.0/24 discard]) +AT_CHECK([ovn-nbctl --policy=src-ip lr-route-add lr0 20.0.0.0/24 discard]) + AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl IPv4 Routes 10.0.0.0/24 11.0.0.1 dst-ip 10.0.1.0/24 11.0.1.1 dst-ip lp0 + 20.0.0.0/24 discard dst-ip 9.16.1.0/24 11.0.0.1 src-ip 10.0.0.0/24 11.0.0.2 src-ip + 20.0.0.0/24 discard src-ip 0.0.0.0/0 192.168.0.1 dst-ip ]) @@ -1487,11 +1495,16 @@ AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl IPv4 Routes 10.0.0.0/24 11.0.0.1 dst-ip lp1 10.0.1.0/24 11.0.1.1 dst-ip lp0 + 20.0.0.0/24 discard dst-ip 9.16.1.0/24 11.0.0.1 src-ip 10.0.0.0/24 11.0.0.2 src-ip + 20.0.0.0/24 discard src-ip 0.0.0.0/0 192.168.0.1 dst-ip ]) +AT_CHECK([ovn-nbctl --policy=src-ip lr-route-del lr0 20.0.0.0/24]) +AT_CHECK([ovn-nbctl lr-route-del lr0 20.0.0.0/24 discard]) + dnl Delete non-existent prefix AT_CHECK([ovn-nbctl lr-route-del lr0 10.0.2.1/24], [1], [], [ovn-nbctl: no matching route: policy 'any', prefix '10.0.2.0/24', nexthop 'any', output_port 'any'. diff --git a/tests/ovn.at b/tests/ovn.at index 55ea6d170..cdbf035fb 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -24049,3 +24049,96 @@ wait_column "true" nb:Logical_Switch_Port up name=lsp1 OVN_CLEANUP([hv1]) AT_CLEANUP + +AT_SETUP([ovn -- Static route with discard nexthop]) +ovn_start + +# Logical network: +# Logical Router lr1 has Logical Switch sw1 (10.0.0.0/24) connected to it. sw1 has one +# switch port sw1-ls1 (10.0.0.100) + +ovn-nbctl lr-add lr1 + +ovn-nbctl ls-add sw1 + +# Connect sw1 to lr1 +ovn-nbctl lrp-add lr1 lr1-sw1 00:00:01:01:02:03 10.0.0.1/24 +ovn-nbctl lsp-add sw1 sw1-lr1 +ovn-nbctl lsp-set-type sw1-lr1 router +ovn-nbctl lsp-set-addresses sw1-lr1 router +ovn-nbctl lsp-set-options sw1-lr1 router-port=lr1-sw1 + +# Create logical port sw1-lp1 in sw1 +ovn-nbctl lsp-add sw1 sw1-lp1 \ +-- lsp-set-addresses sw1-lp1 "00:00:04:01:02:03 10.0.0.100" + +# Create one hypervisor and create OVS ports corresponding to logical ports. +net_add n1 + +sim_add hv1 +as hv1 +ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.1 + +ovs-vsctl -- add-port br-int hv1-vif1 -- \ + set interface hv1-vif1 external-ids:iface-id=sw1-lp1 \ + options:tx_pcap=hv1/vif1-tx.pcap \ + options:rxq_pcap=hv1/vif1-rx.pcap \ + ofport-request=1 + +# Install static routes to drop traffic +ovn-nbctl lr-route-add lr1 20.0.0.0/24 discard + +# Allow some time for ovn-controller to catch up. +ovn-nbctl --wait=hv sync + +# Check logical flows for drop rule +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_ip_routing | grep "20.0.0.0/24" | \ + grep drop | wc -l], [0], [dnl +1 +]) + +# Send packet. +packet="inport==\"sw1-lp1\" && eth.src==00:00:04:01:02:03 && + eth.dst==00:00:01:01:02:03 && ip4 && ip.ttl==64 && + ip4.src==10.0.0.100 && ip4.dst==20.0.0.200 && + udp && udp.src==53 && udp.dst==4369" + +as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet" + +# Check if packet hit the drop rule +AT_CHECK([ovs-ofctl dump-flows br-int | grep "nw_dst=20.0.0.0/24" | \ + grep "actions=drop" | grep "n_packets=1" | wc -l], [0], [dnl +1 +]) + +# Remove destination match and add discard route with source match +ovn-nbctl lr-route-del lr1 20.0.0.0/24 +ovn-nbctl --policy="src-ip" lr-route-add lr1 10.0.0.0/24 discard + +# Allow some time for ovn-controller to catch up. +ovn-nbctl --wait=hv sync + +# Check logical flows for drop rule +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_ip_routing | grep "10.0.0.0/24" | \ + grep drop | wc -l], [0], [dnl +1 +]) + +# Send packet. +packet="inport==\"sw1-lp1\" && eth.src==00:00:04:01:02:03 && + eth.dst==00:00:01:01:02:03 && ip4 && ip.ttl==64 && + ip4.src==10.0.0.100 && ip4.dst==20.0.0.200 && + udp && udp.src==53 && udp.dst==4369" + +as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet" + +# Check if packet hit the drop rule +AT_CHECK([ovs-ofctl dump-flows br-int "nw_src=10.0.0.0/24" | \ + grep "actions=drop" | grep "n_packets=1" | wc -l], [0], [dnl +1 +]) + +OVN_CLEANUP([hv1]) + +AT_CLEANUP diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c index 2c77f4ba7..cab645d83 100644 --- a/utilities/ovn-nbctl.c +++ b/utilities/ovn-nbctl.c @@ -3972,6 +3972,7 @@ nbctl_lr_route_add(struct ctl_context *ctx) const char *policy = shash_find_data(&ctx->options, "--policy"); bool is_src_route = false; + bool is_discard_route = !strcmp(ctx->argv[3], "discard"); if (policy) { if (!strcmp(policy, "src-ip")) { is_src_route = true; @@ -3992,13 +3993,17 @@ nbctl_lr_route_add(struct ctl_context *ctx) return; } - next_hop = v6_prefix - ? normalize_ipv6_addr_str(ctx->argv[3]) - : normalize_ipv4_addr_str(ctx->argv[3]); - if (!next_hop) { - ctl_error(ctx, "bad %s nexthop argument: %s", - v6_prefix ? "IPv6" : "IPv4", ctx->argv[3]); - goto cleanup; + if (is_discard_route) { + next_hop = xasprintf("discard"); + } else { + next_hop = v6_prefix + ? normalize_ipv6_addr_str(ctx->argv[3]) + : normalize_ipv4_addr_str(ctx->argv[3]); + if (!next_hop) { + ctl_error(ctx, "bad %s nexthop argument: %s", + v6_prefix ? "IPv6" : "IPv4", ctx->argv[3]); + goto cleanup; + } } struct shash_node *bfd = shash_find(&ctx->options, "--bfd"); @@ -4047,6 +4052,10 @@ nbctl_lr_route_add(struct ctl_context *ctx) nbrec_logical_router_static_route_set_ip_prefix(route, prefix); nbrec_logical_router_static_route_set_nexthop(route, next_hop); if (ctx->argc == 5) { + if (is_discard_route) { + ctl_error(ctx, "outport is not valid for discard routes."); + goto cleanup; + } nbrec_logical_router_static_route_set_output_port( route, ctx->argv[4]); } @@ -4076,6 +4085,10 @@ nbctl_lr_route_add(struct ctl_context *ctx) nbrec_logical_router_static_route_set_ip_prefix(route, prefix); nbrec_logical_router_static_route_set_nexthop(route, next_hop); if (ctx->argc == 5) { + if (is_discard_route) { + ctl_error(ctx, "outport is not valid for discard routes."); + goto cleanup; + } nbrec_logical_router_static_route_set_output_port(route, ctx->argv[4]); } if (policy) { @@ -4146,10 +4159,14 @@ nbctl_lr_route_del(struct ctl_context *ctx) char *nexthop = NULL; if (ctx->argc >= 4) { - nexthop = normalize_prefix_str(ctx->argv[3]); - if (!nexthop) { - ctl_error(ctx, "bad nexthop argument: %s", ctx->argv[3]); - return; + if (!strcmp(ctx->argv[3], "discard")) { + nexthop = xasprintf("discard"); + } else { + nexthop = normalize_prefix_str(ctx->argv[3]); + if (!nexthop) { + ctl_error(ctx, "bad nexthop argument: %s", ctx->argv[3]); + return; + } } } @@ -4189,9 +4206,12 @@ nbctl_lr_route_del(struct ctl_context *ctx) } /* Compare nexthop, if specified. */ + bool is_discard_route = !strcmp(lr->static_routes[i]->nexthop, + "discard"); if (nexthop) { - char *rt_nexthop = - normalize_prefix_str(lr->static_routes[i]->nexthop); + char *rt_nexthop = is_discard_route + ? xasprintf("discard") + : normalize_prefix_str(lr->static_routes[i]->nexthop); if (!rt_nexthop) { /* Ignore existing nexthop we couldn't parse. */ continue; @@ -5579,7 +5599,9 @@ print_route(const struct nbrec_logical_router_static_route *route, { char *prefix = normalize_prefix_str(route->ip_prefix); - char *next_hop = normalize_prefix_str(route->nexthop); + char *next_hop = !strcmp(route->nexthop, "discard") + ? xasprintf("discard") + : normalize_prefix_str(route->nexthop); ds_put_format(s, "%25s %25s", prefix, next_hop); free(prefix); free(next_hop);