diff options
104 files changed, 5150 insertions, 1107 deletions
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 192cd6ca82..dd27c9f6a1 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -328,7 +328,12 @@ void aspath_free(struct aspath *aspath) void aspath_unintern(struct aspath **aspath) { struct aspath *ret; - struct aspath *asp = *aspath; + struct aspath *asp; + + if (!*aspath) + return; + + asp = *aspath; if (asp->refcnt) asp->refcnt--; diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 4f25f2284f..21f92c353e 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1086,8 +1086,7 @@ void bgp_attr_unintern_sub(struct attr *attr) struct lcommunity *lcomm = NULL; /* aspath refcount shoud be decrement. */ - if (attr->aspath) - aspath_unintern(&attr->aspath); + aspath_unintern(&attr->aspath); UNSET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)); if (attr->community) @@ -3494,14 +3493,12 @@ done: * we can chuck as4_aggregator and as4_path alltogether in order * to save memory */ - if (as4_path) { - /* - * unintern - it is in the hash - * The flag that we got this is still there, but that - * does not do any trouble - */ - aspath_unintern(&as4_path); - } + /* + * unintern - it is in the hash + * The flag that we got this is still there, but that + * does not do any trouble + */ + aspath_unintern(&as4_path); transit = bgp_attr_get_transit(attr); if (ret != BGP_ATTR_PARSE_ERROR) { diff --git a/bgpd/bgp_errors.c b/bgpd/bgp_errors.c index 0f9d5fc73a..f11717b41f 100644 --- a/bgpd/bgp_errors.c +++ b/bgpd/bgp_errors.c @@ -464,7 +464,7 @@ static struct log_ref ferr_bgp_err[] = { }, { .code = EC_BGP_INVALID_BGP_INSTANCE, - .title = "BGP instance for the specifc vrf is invalid", + .title = "BGP instance for the specific vrf is invalid", .description = "Indicates that specified bgp instance is NULL", .suggestion = "Get log files from router and open an issue", }, diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index b5012e4586..eafc37f20c 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -526,7 +526,7 @@ static uint32_t alloc_new_sid(struct bgp *bgp, uint32_t index, struct prefix_ipv6 *chunk; struct in6_addr sid_buf; bool alloced = false; - int label; + int label = 0; if (!bgp || !sid) return false; diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 66c5d862a6..8311cb207c 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2219,8 +2219,16 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, * implementations. */ if (CHECK_FLAG(bgp->flags, BGP_FLAG_EBGP_REQUIRES_POLICY)) - if (!bgp_outbound_policy_exists(peer, filter)) + if (!bgp_outbound_policy_exists(peer, filter)) { + if (monotime_since(&bgp->ebgprequirespolicywarning, + NULL) > FIFTEENMINUTE2USEC || + bgp->ebgprequirespolicywarning.tv_sec == 0) { + zlog_warn( + "EBGP inbound/outbound policy not properly setup, please configure in order for your peering to work correctly"); + monotime(&bgp->ebgprequirespolicywarning); + } return false; + } /* draft-ietf-idr-deprecate-as-set-confed-set * Filter routes having AS_SET or AS_CONFED_SET in the path. @@ -3844,6 +3852,13 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, if (!bgp_inbound_policy_exists(peer, &peer->filter[afi][safi])) { reason = "inbound policy missing"; + if (monotime_since(&bgp->ebgprequirespolicywarning, + NULL) > FIFTEENMINUTE2USEC || + bgp->ebgprequirespolicywarning.tv_sec == 0) { + zlog_warn( + "EBGP inbound/outbound policy not properly setup, please configure in order for your peering to work correctly"); + monotime(&bgp->ebgprequirespolicywarning); + } goto filtered; } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 9a1991cd09..afe4c7ae6f 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -803,11 +803,15 @@ struct peer *peer_and_group_lookup_vty(struct vty *vty, const char *peer_str) return NULL; } -int bgp_vty_return(struct vty *vty, int ret) +int bgp_vty_return(struct vty *vty, enum bgp_create_error_code ret) { const char *str = NULL; switch (ret) { + case BGP_SUCCESS: + case BGP_CREATED: + case BGP_GR_NO_OPERATION: + break; case BGP_ERR_INVALID_VALUE: str = "Invalid value"; break; @@ -877,6 +881,36 @@ int bgp_vty_return(struct vty *vty, int ret) case BGP_ERR_GR_OPERATION_FAILED: str = "The Graceful Restart Operation failed due to an err."; break; + case BGP_ERR_PEER_GROUP_MEMBER: + str = "Peer-group member cannot override remote-as of peer-group."; + break; + case BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT: + str = "Peer-group members must be all internal or all external."; + break; + case BGP_ERR_DYNAMIC_NEIGHBORS_RANGE_NOT_FOUND: + str = "Range specified cannot be deleted because it is not part of current config."; + break; + case BGP_ERR_INSTANCE_MISMATCH: + str = "Instance specified does not match the current instance."; + break; + case BGP_ERR_NO_INTERFACE_CONFIG: + str = "Interface specified is not being used for interface based peer."; + break; + case BGP_ERR_SOFT_RECONFIG_UNCONFIGURED: + str = "No configuration already specified for soft reconfiguration."; + break; + case BGP_ERR_AS_MISMATCH: + str = "BGP is already running."; + break; + case BGP_ERR_AF_UNCONFIGURED: + str = "AFI/SAFI specified is not currently configured."; + break; + case BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS_REMOTE_AS: + str = "AS specified for local as is the same as the remote as and this is not allowed."; + break; + case BGP_ERR_INVALID_AS: + str = "Confederation AS specified is the same AS as our AS."; + break; } if (str) { vty_out(vty, "%% %s\n", str); @@ -4211,17 +4245,6 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str, ret = peer_remote_as(bgp, &su, NULL, &as, as_type); } - /* This peer belongs to peer group. */ - switch (ret) { - case BGP_ERR_PEER_GROUP_MEMBER: - vty_out(vty, - "%% Peer-group member cannot override remote-as of peer-group\n"); - return CMD_WARNING_CONFIG_FAILED; - case BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT: - vty_out(vty, - "%% Peer-group members must be all internal or all external\n"); - return CMD_WARNING_CONFIG_FAILED; - } return bgp_vty_return(vty, ret); } @@ -4958,13 +4981,6 @@ DEFUN (neighbor_set_peer_group, ret = peer_group_bind(bgp, &su, peer, group, &as); - if (ret == BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT) { - vty_out(vty, - "%% Peer with AS %u cannot be in this peer-group, members must be all internal or all external\n", - as); - return CMD_WARNING_CONFIG_FAILED; - } - return bgp_vty_return(vty, ret); } diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index e6d4000ad8..43046f7f18 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -651,9 +651,6 @@ int bgp_confederation_peers_add(struct bgp *bgp, as_t as) struct peer *peer; struct listnode *node, *nnode; - if (!bgp) - return BGP_ERR_INVALID_BGP; - if (bgp->as == as) return BGP_ERR_INVALID_AS; @@ -3239,6 +3236,10 @@ static struct bgp *bgp_create(as_t *as, const char *name, /*initilize global GR FSM */ bgp_global_gr_init(bgp); + + memset(&bgp->ebgprequirespolicywarning, 0, + sizeof(bgp->ebgprequirespolicywarning)); + return bgp; } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index ae6427b356..8b93c450e8 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -759,6 +759,9 @@ struct bgp { struct list *srv6_locator_chunks; struct list *srv6_functions; + struct timeval ebgprequirespolicywarning; +#define FIFTEENMINUTE2USEC (int64_t)15 * 60 * 1000000 + QOBJ_FIELDS; }; DECLARE_QOBJ_TYPE(bgp); @@ -1916,46 +1919,46 @@ enum bgp_clear_type { (((S) == OpenSent) || ((S) == OpenConfirm) || ((S) == Established)) /* BGP error codes. */ -#define BGP_SUCCESS 0 -#define BGP_CREATED 1 -#define BGP_ERR_INVALID_VALUE -1 -#define BGP_ERR_INVALID_FLAG -2 -#define BGP_ERR_INVALID_AS -3 -#define BGP_ERR_INVALID_BGP -4 -#define BGP_ERR_PEER_GROUP_MEMBER -5 -#define BGP_ERR_PEER_GROUP_NO_REMOTE_AS -7 -#define BGP_ERR_PEER_GROUP_CANT_CHANGE -8 -#define BGP_ERR_PEER_GROUP_MISMATCH -9 -#define BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT -10 -#define BGP_ERR_AS_MISMATCH -12 -#define BGP_ERR_PEER_FLAG_CONFLICT -13 -#define BGP_ERR_PEER_GROUP_SHUTDOWN -14 -#define BGP_ERR_PEER_FILTER_CONFLICT -15 -#define BGP_ERR_NOT_INTERNAL_PEER -16 -#define BGP_ERR_REMOVE_PRIVATE_AS -17 -#define BGP_ERR_AF_UNCONFIGURED -18 -#define BGP_ERR_SOFT_RECONFIG_UNCONFIGURED -19 -#define BGP_ERR_INSTANCE_MISMATCH -20 -#define BGP_ERR_LOCAL_AS_ALLOWED_ONLY_FOR_EBGP -21 -#define BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS -22 -#define BGP_ERR_TCPSIG_FAILED -23 -#define BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK -24 -#define BGP_ERR_NO_IBGP_WITH_TTLHACK -25 -#define BGP_ERR_NO_INTERFACE_CONFIG -26 -#define BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS_REMOTE_AS -27 -#define BGP_ERR_AS_OVERRIDE -28 -#define BGP_ERR_INVALID_DYNAMIC_NEIGHBORS_LIMIT -29 -#define BGP_ERR_DYNAMIC_NEIGHBORS_RANGE_EXISTS -30 -#define BGP_ERR_DYNAMIC_NEIGHBORS_RANGE_NOT_FOUND -31 -#define BGP_ERR_INVALID_FOR_DYNAMIC_PEER -32 -#define BGP_ERR_MAX -33 -#define BGP_ERR_INVALID_FOR_DIRECT_PEER -34 -#define BGP_ERR_PEER_SAFI_CONFLICT -35 - -/* BGP GR ERRORS */ -#define BGP_ERR_GR_INVALID_CMD -36 -#define BGP_ERR_GR_OPERATION_FAILED -37 -#define BGP_GR_NO_OPERATION -38 +enum bgp_create_error_code { + BGP_SUCCESS = 0, + BGP_CREATED = 1, + BGP_ERR_INVALID_VALUE = -1, + BGP_ERR_INVALID_FLAG = -2, + BGP_ERR_INVALID_AS = -3, + BGP_ERR_PEER_GROUP_MEMBER = -4, + BGP_ERR_PEER_GROUP_NO_REMOTE_AS = -5, + BGP_ERR_PEER_GROUP_CANT_CHANGE = -6, + BGP_ERR_PEER_GROUP_MISMATCH = -7, + BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT = -8, + BGP_ERR_AS_MISMATCH = -9, + BGP_ERR_PEER_FLAG_CONFLICT = -10, + BGP_ERR_PEER_GROUP_SHUTDOWN = -11, + BGP_ERR_PEER_FILTER_CONFLICT = -12, + BGP_ERR_NOT_INTERNAL_PEER = -13, + BGP_ERR_REMOVE_PRIVATE_AS = -14, + BGP_ERR_AF_UNCONFIGURED = -15, + BGP_ERR_SOFT_RECONFIG_UNCONFIGURED = -16, + BGP_ERR_INSTANCE_MISMATCH = -17, + BGP_ERR_LOCAL_AS_ALLOWED_ONLY_FOR_EBGP = -18, + BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS = -19, + BGP_ERR_TCPSIG_FAILED = -20, + BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK = -21, + BGP_ERR_NO_IBGP_WITH_TTLHACK = -22, + BGP_ERR_NO_INTERFACE_CONFIG = -23, + BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS_REMOTE_AS = -24, + BGP_ERR_AS_OVERRIDE = -25, + BGP_ERR_INVALID_DYNAMIC_NEIGHBORS_LIMIT = -26, + BGP_ERR_DYNAMIC_NEIGHBORS_RANGE_EXISTS = -27, + BGP_ERR_DYNAMIC_NEIGHBORS_RANGE_NOT_FOUND = -28, + BGP_ERR_INVALID_FOR_DYNAMIC_PEER = -29, + BGP_ERR_INVALID_FOR_DIRECT_PEER = -30, + BGP_ERR_PEER_SAFI_CONFLICT = -31, + + /* BGP GR ERRORS */ + BGP_ERR_GR_INVALID_CMD = -32, + BGP_ERR_GR_OPERATION_FAILED = -33, + BGP_GR_NO_OPERATION = -34, +}; /* * Enumeration of different policy kinds a peer can be configured with. diff --git a/configure.ac b/configure.ac index e7bbe329b1..bdddf4b846 100644 --- a/configure.ac +++ b/configure.ac @@ -2587,6 +2587,7 @@ AC_DEFINE_UNQUOTED([ZEBRA_SERV_PATH], ["$frr_statedir%s%s/zserv.api"], [zebra ap AC_DEFINE_UNQUOTED([BFDD_CONTROL_SOCKET], ["$frr_statedir%s%s/bfdd.sock"], [bfdd control socket]) AC_DEFINE_UNQUOTED([OSPFD_GR_STATE], ["$frr_statedir%s/ospfd-gr.json"], [ospfd GR state information]) AC_DEFINE_UNQUOTED([OSPF6D_GR_STATE], ["$frr_statedir/ospf6d-gr.json"], [ospf6d GR state information]) +AC_DEFINE_UNQUOTED([OSPF6_AUTH_SEQ_NUM_FILE], ["$frr_statedir/ospf6d-at-seq-no.dat"], [ospf6d AT Sequence number information]) AC_DEFINE_UNQUOTED([DAEMON_VTY_DIR], ["$frr_statedir%s%s"], [daemon vty directory]) AC_DEFINE_UNQUOTED([DAEMON_DB_DIR], ["$frr_statedir"], [daemon database directory]) diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst index 2005e9d8bb..45bee17b71 100644 --- a/doc/developer/workflow.rst +++ b/doc/developer/workflow.rst @@ -141,6 +141,16 @@ March/July/November. Walking backwards from this date: - 2 weeks earlier, a ``frr-X.Y-rc`` release candidate is tagged. + .. code-block:: console + + % git remote --verbose + upstream git@github.com:frrouting/frr (fetch) + upstream git@github.com:frrouting/frr (push) + + % git checkout dev/8.2 + % git tag frr-8.2-rc + % git push upstream frr-8.2-rc + - on release date, the branch is renamed to ``stable/MAJOR.MINOR``. The 2 week window between each of these events should be used to run any and diff --git a/doc/manpages/vtysh.rst b/doc/manpages/vtysh.rst index b930cb915d..af527bea40 100644 --- a/doc/manpages/vtysh.rst +++ b/doc/manpages/vtysh.rst @@ -74,7 +74,7 @@ VTYSH_PAGER VTYSH_HISTFILE Override the history file for vtysh commands. Logging can be turned off using ``VTYSH_HISTFILE=/dev/null vtysh``. - Environment is prefered way to override the history file path over command line argument (-H/--histfile). + Environment is preferred way to override the history file path over command line argument (-H/--histfile). FILES ===== diff --git a/doc/user/ospf6d.rst b/doc/user/ospf6d.rst index 624510323c..8dacb9c9dc 100644 --- a/doc/user/ospf6d.rst +++ b/doc/user/ospf6d.rst @@ -383,6 +383,256 @@ Graceful Restart This is an EXEC-level command. +.. _Authentication-trailer: + +Authentication trailer support: +=============================== +IPv4 version of OSPF supports authentication as part of the base RFC. +When IPv6 version of OSPF was developed there was IPSec support for IPv6, +Hence OSPFv3(IPv6 version of OSPF) suggest to use IPSec as authentication +and encryption mechanism. IPSec supports authentication using AH header and +Encryption using ESP. + +There are few disadvantages of using IPSec with OSPFv3. + 1. If encryption is enabled for OSPFv3 packets, then its not + possible to give priority to control packets. + 2. IPSec has platform dependency and may not be supported + in all platforms. + 3. It is performance intensive. + 4. Its difficult to configure. + + +Some advantages of OSPFv3 authentication trailer feature. + 1. It provides replay protection via sequence number. + 2. It provides IPv6 source address protection. + 3. No platform dependency. + 4. Easy to implement and maintain. + + +This feature is support for ``RFC7166``. + +FRR supports MD5 and SHA256 internally and relays on openssl for other hash +algorithms. If user wants to use only MD5 and SHA256, no special action is +required. If user wants complete support of authentication trailer with all +hash algorithms follow below steps. + + +Installing Dependencies: +------------------------ + +.. code-block:: console + + sudo apt update + sudo apt-get install openssl + + +Compile: +-------- +Follow normal compilation as mentioned in the build page. If you want to +use all the hash algorithms then follow the steps mentioned in note before +compiling. + + +.. note:: + + If your platform supports ``openssl``, please make sure to add + ``--with-crypto=openssl`` to your configure options. + Default value is ``--with-crypto=internal`` + + +CLI Configuration: +------------------ +There are two ways in which authentication trailer can be configured for +OSPFv3. These commands are mutually exclusive, only one can be configured +at any time. + + 1. Using manual key configuration. + 2. Using keychain. + + +List of hash algorithms supported: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Without openssl: +++++++++++++++++ + ``MD5`` + ``HMAC-SHA-256`` + + +With openssl: ++++++++++++++ + ``MD5`` + ``HMAC-SHA-1`` + ``HMAC-SHA-256`` + ``HMAC-SHA-384`` + ``HMAC-SHA-512`` + + +Example configuration of manual key: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Without openssl: +++++++++++++++++ + +.. clicmd:: ipv6 ospf6 authentication key-id (1-65535) hash-algo <md5|hmac-sha-256> key WORD + +With openssl: ++++++++++++++ + +.. clicmd:: ipv6 ospf6 authentication key-id (1-65535) hash-algo <md5|hmac-sha-256|hmac-sha-1|hmac-sha-384|hmac-sha-512> key WORD + + +Example configuration of keychain: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. clicmd:: ipv6 ospf6 authentication keychain KEYCHAIN_NAME + + +Running configuration: +---------------------- + +Manual key: +^^^^^^^^^^^ + +.. code-block:: frr + + frr# show running-config + Building configuration... + + Current configuration: + ! + interface ens192 + ipv6 address 2001:DB8::2/64 + ipv6 ospf6 authentication key-id 10 hash-algo hmac-sha-256 key abhinay + +Keychain: +^^^^^^^^^ + +.. code-block:: frr + + frr# show running-config + Building configuration... + + Current configuration: + ! + interface ens192 + ipv6 address 2001:DB8::2/64 + ipv6 ospf6 authentication keychain abhinay + + +Example keychain config: +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: frr + + frr#show running-config + Building configuration... + + Current configuration: + ! + key chain abcd + key 100 + key-string password + cryptographic-algorithm sha1 + exit + key 200 + key-string password + cryptographic-algorithm sha256 + exit + ! + key chain pqr + key 300 + key-string password + cryptographic-algorithm sha384 + exit + key 400 + key-string password + cryptographic-algorithm sha384 + exit + ! + +Show commands: +-------------- +There is an interface show command that displays if authentication trailer +is enabled or not. json output is also supported. + +There is support for drop counters, which will help in debugging the feature. + +.. code-block:: frr + + frr# show ipv6 ospf6 interface ens192 + ens192 is up, type BROADCAST + Interface ID: 5 + Number of I/F scoped LSAs is 2 + 0 Pending LSAs for LSUpdate in Time 00:00:00 [thread off] + 0 Pending LSAs for LSAck in Time 00:00:00 [thread off] + Authentication trailer is enabled with manual key ==> new info added + Packet drop Tx 0, Packet drop Rx 0 + + +OSPFv3 supports options in hello and database description packets hence +the presence of authentication trailer needs to be stored in OSPFv3 +neighbor info. Since RFC specifies that we need to handled sequence number +for every ospf6 packet type, sequence number recvd in authentication header +from the neighbor is stored in neighbor to validate the packet. +json output is also supported. + +.. code-block:: frr + + frr# show ipv6 ospf6 neighbor 2.2.2.2 detail + Neighbor 2.2.2.2%ens192 + Area 1 via interface ens192 (ifindex 3) + 0 Pending LSAs for LSUpdate in Time 00:00:00 [thread off] + 0 Pending LSAs for LSAck in Time 00:00:00 [thread off] + Authentication header present ==> new info added + hello DBDesc LSReq LSUpd LSAck + Higher sequence no 0x0 0x0 0x0 0x0 0x0 + Lower sequence no 0x242E 0x1DC4 0x1DC3 0x23CC 0x1DDA + +Sent packet sequence number is maintained per ospf6 router for every packet +that is sent out of router, so sequence number is maintained per ospf6 process. + +.. code-block:: frr + + frr# show ipv6 ospf6 + OSPFv3 Routing Process (0) with Router-ID 2.2.2.2 + Number of areas in this router is 1 + Authentication Sequence number info + Higher sequence no 3, Lower sequence no 1656 + +Debug command: +-------------- +Below command can be used to enable ospfv3 authentication trailer +specific logs if you have to debug the feature. + +.. clicmd:: debug ospf6 authentication [<tx|rx>] + +Feature supports authentication trailer tx/rx drop counters for debugging, +which can be used to see if packets are getting dropped due to error in +processing authentication trailer information in OSPFv3 packet. +json output is also supported. + +.. code-block:: frr + + frr# show ipv6 ospf6 interface ens192 + ens192 is up, type BROADCAST + Interface ID: 5 + Number of I/F scoped LSAs is 2 + 0 Pending LSAs for LSUpdate in Time 00:00:00 [thread off] + 0 Pending LSAs for LSAck in Time 00:00:00 [thread off] + Authentication trailer is enabled with manual key + Packet drop Tx 0, Packet drop Rx 0 ==> new counters + +Clear command: +-------------- +Below command can be used to clear the tx/rx drop counters in interface. +Below command can be used to clear all ospfv3 interface or specific +interface by specifying the interface name. + +.. clicmd:: clear ipv6 ospf6 auth-counters interface [IFNAME] + + + .. _showing-ospf6-information: Showing OSPF6 information @@ -431,7 +681,7 @@ Showing OSPF6 information .. clicmd:: show ipv6 ospf6 [vrf <NAME|all>] interface traffic [json] - Shows counts of different packets that have been recieved and transmitted + Shows counts of different packets that have been received and transmitted by the interfaces. JSON output can be obtained by appending "json" at the end. diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst index ed4d02d89b..d1a0bb6f7b 100644 --- a/doc/user/ospfd.rst +++ b/doc/user/ospfd.rst @@ -268,8 +268,10 @@ To start OSPF process you have to specify the OSPF router. the destination prefix. Otherwise, we test whether the network command prefix contains the local address prefix of the interface. - In some cases it may be more convenient to enable OSPF on a per - interface/subnet basis (:clicmd:`ip ospf area AREA [ADDR]`). + It is also possible to enable OSPF on a per interface/subnet basis + using the interface command (:clicmd:`ip ospf area AREA [ADDR]`). + However, mixing both network commands (:clicmd:`network`) and interface + commands (:clicmd:`ip ospf`) on the same router is not supported. .. clicmd:: proactive-arp @@ -313,9 +315,9 @@ To start OSPF process you have to specify the OSPF router. Areas ----- -.. clicmd:: area A.B.C.D range A.B.C.D/M +.. clicmd:: area A.B.C.D range A.B.C.D/M [advertise [cost (0-16777215)]] -.. clicmd:: area (0-4294967295) range A.B.C.D/M +.. clicmd:: area (0-4294967295) range A.B.C.D/M [advertise [cost (0-16777215)]] @@ -346,9 +348,9 @@ Areas range are not advertised into other areas. This command makes sense in ABR only. -.. clicmd:: area A.B.C.D range A.B.C.D/M substitute A.B.C.D/M +.. clicmd:: area A.B.C.D range A.B.C.D/M {substitute A.B.C.D/M|cost (0-16777215)} -.. clicmd:: area (0-4294967295) range A.B.C.D/M substitute A.B.C.D/M +.. clicmd:: area (0-4294967295) range A.B.C.D/M {substitute A.B.C.D/M|cost (0-16777215)} Substitute summarized prefix with another prefix. @@ -364,6 +366,11 @@ Areas One Type-3 summary-LSA with routing info 11.0.0.0/8 is announced into backbone area if area 0.0.0.10 contains at least one intra-area network (i.e. described with router-LSA or network-LSA) from range 10.0.0.0/8. + + By default, the metric of the summary route is calculated as the highest + metric among the summarized routes. The `cost` option, however, can be used + to set an explicit metric. + This command makes sense in ABR only. .. clicmd:: area A.B.C.D virtual-link A.B.C.D @@ -510,12 +517,14 @@ Interfaces Enable OSPF on the interface, optionally restricted to just the IP address - given by `ADDR`, putting it in the `AREA` area. Per interface area settings - take precedence to network commands - (:clicmd:`network A.B.C.D/M area A.B.C.D`). - - If you have a lot of interfaces, and/or a lot of subnets, then enabling OSPF - via this command may result in a slight performance improvement. + given by `ADDR`, putting it in the `AREA` area. If you have a lot of + interfaces, and/or a lot of subnets, then enabling OSPF via this command + instead of (:clicmd:`network A.B.C.D/M area A.B.C.D`) may result in a + slight performance improvement. + + Notice that, mixing both network commands (:clicmd:`network`) and interface + commands (:clicmd:`ip ospf`) on the same router is not supported. + If (:clicmd:`ip ospf`) is present, (:clicmd:`network`) commands will fail. .. clicmd:: ip ospf authentication-key AUTH_KEY diff --git a/doc/user/pim.rst b/doc/user/pim.rst index 306feec0f7..1c3a0110ac 100644 --- a/doc/user/pim.rst +++ b/doc/user/pim.rst @@ -176,7 +176,7 @@ Certain signals have special meanings to *pimd*. Generate IGMP query (v2/v3) on user requirement. This will not depend on the existing IGMP general query timer.If no version is provided in the cli, - it will be considered as default v2 query.This is a hidden command. + the default will be the igmp version enabled on that interface. .. clicmd:: ip igmp watermark-warn (1-65535) @@ -393,7 +393,7 @@ cause great confusion. Display IGMP group retransmission information. -.. clicmd:: show ip igmp sources +.. clicmd:: show ip igmp [vrf NAME] sources [json] Display IGMP sources information. diff --git a/lib/keychain.c b/lib/keychain.c index 02f83ef0a8..c29c45a114 100644 --- a/lib/keychain.c +++ b/lib/keychain.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "config.h" #include <zebra.h> #include "command.h" @@ -207,6 +208,7 @@ static struct key *key_get(const struct keychain *keychain, uint32_t index) key = key_new(); key->index = index; + key->hash_algo = KEYCHAIN_ALGO_NULL; listnode_add_sort(keychain->key, key); return key; @@ -336,6 +338,133 @@ DEFUN (no_key_string, return CMD_SUCCESS; } +const struct keychain_algo_info algo_info[] = { + {KEYCHAIN_ALGO_NULL, "null", 0, 0, "NULL"}, + {KEYCHAIN_ALGO_MD5, "md5", KEYCHAIN_MD5_HASH_SIZE, + KEYCHAIN_ALGO_MD5_INTERNAL_BLK_SIZE, "MD5"}, + {KEYCHAIN_ALGO_HMAC_SHA1, "hmac-sha-1", KEYCHAIN_HMAC_SHA1_HASH_SIZE, + KEYCHAIN_ALGO_SHA1_INTERNAL_BLK_SIZE, "HMAC-SHA-1"}, + {KEYCHAIN_ALGO_HMAC_SHA256, "hmac-sha-256", + KEYCHAIN_HMAC_SHA256_HASH_SIZE, KEYCHAIN_ALGO_SHA256_INTERNAL_BLK_SIZE, + "HMAC-SHA-256"}, + {KEYCHAIN_ALGO_HMAC_SHA384, "hmac-sha-384", + KEYCHAIN_HMAC_SHA384_HASH_SIZE, KEYCHAIN_ALGO_SHA384_INTERNAL_BLK_SIZE, + "HMAC-SHA-384"}, + {KEYCHAIN_ALGO_HMAC_SHA512, "hmac-sha-512", + KEYCHAIN_HMAC_SHA512_HASH_SIZE, KEYCHAIN_ALGO_SHA512_INTERNAL_BLK_SIZE, + "HMAC-SHA-512"}, + {KEYCHAIN_ALGO_MAX, "max", KEYCHAIN_MAX_HASH_SIZE, + KEYCHAIN_ALGO_MAX_INTERNAL_BLK_SIZE, "Not defined"} +}; + +uint16_t keychain_get_block_size(enum keychain_hash_algo key) +{ + return algo_info[key].block; +} + +uint16_t keychain_get_hash_len(enum keychain_hash_algo key) +{ + return algo_info[key].length; +} + +const char *keychain_get_description(enum keychain_hash_algo key) +{ + return algo_info[key].desc; +} + +struct keychain_algo_info +keychain_get_hash_algo_info(enum keychain_hash_algo key) +{ + return algo_info[key]; +} + +enum keychain_hash_algo keychain_get_algo_id_by_name(const char *name) +{ +#ifdef CRYPTO_INTERNAL + if (!strncmp(name, "hmac-sha-2", 10)) + return KEYCHAIN_ALGO_HMAC_SHA256; + else if (!strncmp(name, "m", 1)) + return KEYCHAIN_ALGO_MD5; + else + return KEYCHAIN_ALGO_NULL; +#else + if (!strncmp(name, "m", 1)) + return KEYCHAIN_ALGO_MD5; + else if (!strncmp(name, "hmac-sha-1", 10)) + return KEYCHAIN_ALGO_HMAC_SHA1; + else if (!strncmp(name, "hmac-sha-2", 10)) + return KEYCHAIN_ALGO_HMAC_SHA256; + else if (!strncmp(name, "hmac-sha-3", 10)) + return KEYCHAIN_ALGO_HMAC_SHA384; + else if (!strncmp(name, "hmac-sha-5", 10)) + return KEYCHAIN_ALGO_HMAC_SHA512; + else + return KEYCHAIN_ALGO_NULL; +#endif +} + +const char *keychain_get_algo_name_by_id(enum keychain_hash_algo key) +{ + return algo_info[key].name; +} + +DEFUN(cryptographic_algorithm, cryptographic_algorithm_cmd, + "cryptographic-algorithm " + "<md5|hmac-sha-1|hmac-sha-256|hmac-sha-384|hmac-sha-512>", + "Cryptographic-algorithm\n" + "Use MD5 algorithm\n" + "Use HMAC-SHA-1 algorithm\n" + "Use HMAC-SHA-256 algorithm\n" + "Use HMAC-SHA-384 algorithm\n" + "Use HMAC-SHA-512 algorithm\n") +{ + int algo_idx = 1; + uint8_t hash_algo = KEYCHAIN_ALGO_NULL; + + VTY_DECLVAR_CONTEXT_SUB(key, key); + hash_algo = keychain_get_algo_id_by_name(argv[algo_idx]->arg); +#ifndef CRYPTO_OPENSSL + if (hash_algo == KEYCHAIN_ALGO_NULL) { + vty_out(vty, + "Hash algorithm not supported, compile with --with-crypto=openssl\n"); + return CMD_WARNING_CONFIG_FAILED; + } +#endif /* CRYPTO_OPENSSL */ + key->hash_algo = hash_algo; + return CMD_SUCCESS; +} + +DEFUN(no_cryptographic_algorithm, no_cryptographic_algorithm_cmd, + "no cryptographic-algorithm " + "[<md5|hmac-sha-1|hmac-sha-256|hmac-sha-384|hmac-sha-512>]", + NO_STR + "Cryptographic-algorithm\n" + "Use MD5 algorithm\n" + "Use HMAC-SHA-1 algorithm\n" + "Use HMAC-SHA-256 algorithm\n" + "Use HMAC-SHA-384 algorithm\n" + "Use HMAC-SHA-512 algorithm\n") +{ + int algo_idx = 2; + uint8_t hash_algo = KEYCHAIN_ALGO_NULL; + + VTY_DECLVAR_CONTEXT_SUB(key, key); + if (argc > algo_idx) { + hash_algo = keychain_get_algo_id_by_name(argv[algo_idx]->arg); + if (hash_algo == KEYCHAIN_ALGO_NULL) { + vty_out(vty, + "Hash algorithm not supported, try compiling with --with-crypto=openssl\n"); + return CMD_WARNING_CONFIG_FAILED; + } + } + + if ((hash_algo != KEYCHAIN_ALGO_NULL) && (hash_algo != key->hash_algo)) + return CMD_SUCCESS; + + key->hash_algo = KEYCHAIN_ALGO_NULL; + return CMD_SUCCESS; +} + /* Convert HH:MM:SS MON DAY YEAR to time_t value. -1 is returned when given string is malformed. */ static time_t key_str2time(const char *time_str, const char *day_str, @@ -1004,6 +1133,11 @@ static int keychain_config_write(struct vty *vty) if (key->string) vty_out(vty, " key-string %s\n", key->string); + if (key->hash_algo != KEYCHAIN_ALGO_NULL) + vty_out(vty, " cryptographic-algorithm %s\n", + keychain_get_algo_name_by_id( + key->hash_algo)); + if (key->accept.start) { keychain_strftime(buf, BUFSIZ, &key->accept.start); @@ -1051,10 +1185,29 @@ static int keychain_config_write(struct vty *vty) return 0; } + +static void keychain_active_config(vector comps, struct cmd_token *token) +{ + struct keychain *keychain; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(keychain_list, node, keychain)) + vector_set(comps, XSTRDUP(MTYPE_COMPLETION, keychain->name)); +} + +static const struct cmd_variable_handler keychain_var_handlers[] = { + {.varname = "key_chain", .completions = keychain_active_config}, + {.tokenname = "KEYCHAIN_NAME", .completions = keychain_active_config}, + {.tokenname = "KCHAIN_NAME", .completions = keychain_active_config}, + {.completions = NULL} +}; + void keychain_init(void) { keychain_list = list_new(); + /* Register handler for keychain auto config support */ + cmd_variable_handler_register(keychain_var_handlers); install_node(&keychain_node); install_node(&keychain_key_node); @@ -1113,4 +1266,6 @@ void keychain_init(void) install_element(KEYCHAIN_KEY_NODE, &send_lifetime_duration_month_day_cmd); install_element(KEYCHAIN_KEY_NODE, &no_send_lifetime_cmd); + install_element(KEYCHAIN_KEY_NODE, &cryptographic_algorithm_cmd); + install_element(KEYCHAIN_KEY_NODE, &no_cryptographic_algorithm_cmd); } diff --git a/lib/keychain.h b/lib/keychain.h index eb6d2f175e..71319d9722 100644 --- a/lib/keychain.h +++ b/lib/keychain.h @@ -27,6 +27,47 @@ extern "C" { #endif +enum keychain_hash_algo { + KEYCHAIN_ALGO_NULL, + KEYCHAIN_ALGO_MD5, + KEYCHAIN_ALGO_HMAC_SHA1, + KEYCHAIN_ALGO_HMAC_SHA256, + KEYCHAIN_ALGO_HMAC_SHA384, + KEYCHAIN_ALGO_HMAC_SHA512, + KEYCHAIN_ALGO_MAX +}; + +#define KEYCHAIN_MD5_HASH_SIZE 16 +#define KEYCHAIN_HMAC_SHA1_HASH_SIZE 20 +#define KEYCHAIN_HMAC_SHA256_HASH_SIZE 32 +#define KEYCHAIN_HMAC_SHA384_HASH_SIZE 48 +#define KEYCHAIN_HMAC_SHA512_HASH_SIZE 64 +#define KEYCHAIN_MAX_HASH_SIZE 64 + +#define KEYCHAIN_ALGO_MD5_INTERNAL_BLK_SIZE 16 +#define KEYCHAIN_ALGO_SHA1_INTERNAL_BLK_SIZE 64 +#define KEYCHAIN_ALGO_SHA256_INTERNAL_BLK_SIZE 64 +#define KEYCHAIN_ALGO_SHA384_INTERNAL_BLK_SIZE 128 +#define KEYCHAIN_ALGO_SHA512_INTERNAL_BLK_SIZE 128 +#define KEYCHAIN_ALGO_MAX_INTERNAL_BLK_SIZE 128 + +struct keychain_algo_info { + enum keychain_hash_algo key; + const char *name; + uint16_t length; + uint16_t block; + const char *desc; +}; + +extern const struct keychain_algo_info algo_info[]; +uint16_t keychain_get_block_size(enum keychain_hash_algo key); +uint16_t keychain_get_hash_len(enum keychain_hash_algo key); +const char *keychain_get_description(enum keychain_hash_algo key); +struct keychain_algo_info +keychain_get_hash_algo_info(enum keychain_hash_algo key); +enum keychain_hash_algo keychain_get_algo_id_by_name(const char *name); +const char *keychain_get_algo_name_by_id(enum keychain_hash_algo key); + struct keychain { char *name; @@ -47,7 +88,7 @@ struct key { uint32_t index; char *string; - + enum keychain_hash_algo hash_algo; struct key_range send; struct key_range accept; @@ -60,7 +101,7 @@ extern struct keychain *keychain_lookup(const char *); extern struct key *key_lookup_for_accept(const struct keychain *, uint32_t); extern struct key *key_match_for_accept(const struct keychain *, const char *); extern struct key *key_lookup_for_send(const struct keychain *); - +const char *keychain_algo_str(enum keychain_hash_algo hash_algo); #ifdef __cplusplus } #endif diff --git a/lib/thread.c b/lib/thread.c index 376f61c247..ada7a9cc80 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -138,11 +138,12 @@ static void cpu_record_hash_free(void *a) static void vty_out_cpu_thread_history(struct vty *vty, struct cpu_thread_history *a) { - vty_out(vty, "%5zu %10zu.%03zu %9zu %8zu %9zu %8zu %9zu %9zu %9zu", + vty_out(vty, + "%5zu %10zu.%03zu %9zu %8zu %9zu %8zu %9zu %9zu %9zu %10zu", a->total_active, a->cpu.total / 1000, a->cpu.total % 1000, a->total_calls, (a->cpu.total / a->total_calls), a->cpu.max, (a->real.total / a->total_calls), a->real.max, - a->total_cpu_warn, a->total_wall_warn); + a->total_cpu_warn, a->total_wall_warn, a->total_starv_warn); vty_out(vty, " %c%c%c%c%c %s\n", a->types & (1 << THREAD_READ) ? 'R' : ' ', a->types & (1 << THREAD_WRITE) ? 'W' : ' ', @@ -168,6 +169,8 @@ static void cpu_record_hash_print(struct hash_bucket *bucket, void *args[]) atomic_load_explicit(&a->total_cpu_warn, memory_order_seq_cst); copy.total_wall_warn = atomic_load_explicit(&a->total_wall_warn, memory_order_seq_cst); + copy.total_starv_warn = atomic_load_explicit(&a->total_starv_warn, + memory_order_seq_cst); copy.cpu.total = atomic_load_explicit(&a->cpu.total, memory_order_seq_cst); copy.cpu.max = atomic_load_explicit(&a->cpu.max, memory_order_seq_cst); @@ -186,6 +189,7 @@ static void cpu_record_hash_print(struct hash_bucket *bucket, void *args[]) totals->total_calls += copy.total_calls; totals->total_cpu_warn += copy.total_cpu_warn; totals->total_wall_warn += copy.total_wall_warn; + totals->total_starv_warn += copy.total_starv_warn; totals->real.total += copy.real.total; if (totals->real.max < copy.real.max) totals->real.max = copy.real.max; @@ -231,7 +235,8 @@ static void cpu_record_print(struct vty *vty, uint8_t filter) vty_out(vty, "Active Runtime(ms) Invoked Avg uSec Max uSecs"); vty_out(vty, " Avg uSec Max uSecs"); - vty_out(vty, " CPU_Warn Wall_Warn Type Thread\n"); + vty_out(vty, + " CPU_Warn Wall_Warn Starv_Warn Type Thread\n"); if (m->cpu_record->count) hash_iterate( @@ -1668,13 +1673,17 @@ static unsigned int thread_process_timers(struct thread_master *m, * really getting behind on handling of events. * Let's log it and do the right thing with it. */ - if (!displayed && !thread->ignore_timer_late && - timercmp(timenow, &prev, >)) { - flog_warn( - EC_LIB_STARVE_THREAD, - "Thread Starvation: %pTHD was scheduled to pop greater than 4s ago", - thread); - displayed = true; + if (timercmp(timenow, &prev, >)) { + atomic_fetch_add_explicit( + &thread->hist->total_starv_warn, 1, + memory_order_seq_cst); + if (!displayed && !thread->ignore_timer_late) { + flog_warn( + EC_LIB_STARVE_THREAD, + "Thread Starvation: %pTHD was scheduled to pop greater than 4s ago", + thread); + displayed = true; + } } thread_timer_list_pop(&m->timer); diff --git a/lib/thread.h b/lib/thread.h index 660f8bd28e..0c2a4ba869 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -137,6 +137,7 @@ struct cpu_thread_history { int (*func)(struct thread *); atomic_size_t total_cpu_warn; atomic_size_t total_wall_warn; + atomic_size_t total_starv_warn; atomic_size_t total_calls; atomic_size_t total_active; struct time_stats { diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 203ae14f2d..1c0d948cca 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -2874,7 +2874,7 @@ ospf6_originate_summary_lsa(struct ospf6 *ospf6, if (IS_OSPF6_DEBUG_AGGR) zlog_debug("%s: Aggr LSA ID: %d flags %x.", __func__, aggr->id, aggr->aggrflags); - /* Dont originate external LSA, + /* Don't originate external LSA, * If it is configured not to advertise. */ if (CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE)) { @@ -3248,11 +3248,11 @@ static void ospf6_handle_aggregated_exnl_rt(struct ospf6 *ospf6, /* Handling the case where the external route prefix * and aggegate prefix is same - * If same dont flush the originated external LSA. + * If same don't flush the originated external LSA. */ if (prefix_same(&aggr->p, &rt->prefix)) { if (IS_OSPF6_DEBUG_AGGR) - zlog_debug("%s: External Route prefix same as Aggregator(%pFX), so dont flush.", + zlog_debug("%s: External Route prefix same as Aggregator(%pFX), so don't flush.", __func__, &rt->prefix); @@ -3623,7 +3623,7 @@ void ospf6_handle_external_lsa_origination(struct ospf6 *ospf6, /* Handling the case where the * external route prefix * and aggegate prefix is same - * If same dont flush the + * If same don't flush the * originated * external LSA. */ diff --git a/ospf6d/ospf6_auth_trailer.c b/ospf6d/ospf6_auth_trailer.c new file mode 100644 index 0000000000..1095473f4a --- /dev/null +++ b/ospf6d/ospf6_auth_trailer.c @@ -0,0 +1,1000 @@ +/* + * Copyright (C) 2021 Abhinay Ramesh + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "zebra.h" +#include "config.h" +#include "memory.h" +#include "ospf6d.h" +#include "vty.h" +#include "command.h" +#include "md5.h" +#include "sha256.h" +#include "lib/zlog.h" +#include "ospf6_message.h" +#include "ospf6_interface.h" +#include "ospf6_neighbor.h" +#include "ospf6_proto.h" +#include "ospf6_top.h" +#include "ospf6_area.h" +#include "ospf6_auth_trailer.h" +#include "ospf6_route.h" +#include "ospf6_zebra.h" +#include "lib/keychain.h" + +unsigned char conf_debug_ospf6_auth[2]; +DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_AUTH_HASH_XOR, "OSPF6 auth hash xor"); + +/*Apad is the hexadecimal value 0x878FE1F3. */ +const uint8_t ospf6_hash_apad_max[KEYCHAIN_MAX_HASH_SIZE] = { + 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, + 0xf3, 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, + 0xe1, 0xf3, 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, 0xf3, 0x87, + 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, 0xf3, + 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, + 0xf3, 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, 0xf3, +}; + +const uint8_t ospf6_hash_ipad_max[KEYCHAIN_ALGO_MAX_INTERNAL_BLK_SIZE] = { + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +}; + +const uint8_t ospf6_hash_opad_max[KEYCHAIN_ALGO_MAX_INTERNAL_BLK_SIZE] = { + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, +}; + +void ospf6_auth_hdr_dump_send(struct ospf6_header *ospfh, uint16_t length) +{ + struct ospf6_auth_hdr *ospf6_at_hdr; + uint16_t at_len, oh_len, at_hdr_len, hash_len; + unsigned char temp[KEYCHAIN_MAX_HASH_SIZE + 1]; + + oh_len = htons(ospfh->length); + at_len = length - oh_len; + if (at_len > 0) { + ospf6_at_hdr = (struct ospf6_auth_hdr *) + ((uint8_t *)ospfh + oh_len); + at_hdr_len = htons(ospf6_at_hdr->length); + hash_len = at_hdr_len - OSPF6_AUTH_HDR_MIN_SIZE; + memcpy(temp, ospf6_at_hdr->data, hash_len); + temp[hash_len] = '\0'; + zlog_debug("OSPF6 Authentication Trailer"); + zlog_debug(" Type %d", htons(ospf6_at_hdr->type)); + zlog_debug(" Length %d", at_hdr_len); + zlog_debug(" Reserved %d", ospf6_at_hdr->reserved); + zlog_debug(" SA ID %d", htons(ospf6_at_hdr->id)); + zlog_debug(" seqnum high 0x%08x", + htonl(ospf6_at_hdr->seqnum_h)); + zlog_debug(" seqnum high 0x%08x", + htonl(ospf6_at_hdr->seqnum_l)); + zlog_debug(" Data %s", temp); + } +} + +void ospf6_auth_hdr_dump_recv(struct ospf6_header *ospfh, uint16_t length, + unsigned int lls_len) +{ + struct ospf6_auth_hdr *ospf6_at_hdr; + uint16_t at_len, oh_len, at_hdr_len, hash_len; + unsigned char temp[KEYCHAIN_MAX_HASH_SIZE + 1]; + + oh_len = ntohs(ospfh->length); + at_len = length - (oh_len + lls_len); + if (at_len > 0) { + ospf6_at_hdr = + (struct ospf6_auth_hdr *)((uint8_t *)ospfh + oh_len); + at_hdr_len = ntohs(ospf6_at_hdr->length); + hash_len = at_hdr_len - OSPF6_AUTH_HDR_MIN_SIZE; + memcpy(temp, ospf6_at_hdr->data, hash_len); + temp[hash_len] = '\0'; + zlog_debug("OSPF6 Authentication Trailer"); + zlog_debug(" Type %d", ntohs(ospf6_at_hdr->type)); + zlog_debug(" Length %d", at_hdr_len); + zlog_debug(" Reserved %d", ospf6_at_hdr->reserved); + zlog_debug(" SA ID %d", ntohs(ospf6_at_hdr->id)); + zlog_debug(" seqnum high 0x%08x", + ntohl(ospf6_at_hdr->seqnum_h)); + zlog_debug(" seqnum high 0x%08x", + ntohl(ospf6_at_hdr->seqnum_l)); + zlog_debug(" Data %s", temp); + } +} + +unsigned char *ospf6_hash_message_xor(unsigned char *mes1, + unsigned char *mes2, + uint32_t len) +{ + unsigned char *result; + uint32_t i; + + result = XCALLOC(MTYPE_OSPF6_AUTH_HASH_XOR, len); + if (!result) + return NULL; + + for (i = 0; i < len; i++) + result[i] = mes1[i] ^ mes2[i]; + + return result; +} + +static void md5_digest(unsigned char *mes, uint32_t len, + unsigned char *digest) +{ +#ifdef CRYPTO_OPENSSL + unsigned int size = KEYCHAIN_MD5_HASH_SIZE; + EVP_MD_CTX *ctx; +#elif CRYPTO_INTERNAL + MD5_CTX ctx; +#endif + +#ifdef CRYPTO_OPENSSL + ctx = EVP_MD_CTX_new(); + EVP_DigestInit(ctx, EVP_md5()); + EVP_DigestUpdate(ctx, mes, len); + EVP_DigestFinal(ctx, digest, &size); + EVP_MD_CTX_free(ctx); +#elif CRYPTO_INTERNAL + memset(&ctx, 0, sizeof(ctx)); + MD5Init(&ctx); + MD5Update(&ctx, mes, len); + MD5Final(digest, &ctx); +#endif +} + +static void sha256_digest(unsigned char *mes, uint32_t len, + unsigned char *digest) +{ +#ifdef CRYPTO_OPENSSL + unsigned int size = KEYCHAIN_HMAC_SHA256_HASH_SIZE; + EVP_MD_CTX *ctx; +#elif CRYPTO_INTERNAL + SHA256_CTX ctx; +#endif + +#ifdef CRYPTO_OPENSSL + ctx = EVP_MD_CTX_new(); + EVP_DigestInit(ctx, EVP_sha256()); + EVP_DigestUpdate(ctx, mes, len); + EVP_DigestFinal(ctx, digest, &size); + EVP_MD_CTX_free(ctx); +#elif CRYPTO_INTERNAL + memset(&ctx, 0, sizeof(ctx)); + SHA256_Init(&ctx); + SHA256_Update(&ctx, mes, len); + SHA256_Final(digest, &ctx); +#endif +} + +#ifdef CRYPTO_OPENSSL +static void sha1_digest(unsigned char *mes, uint32_t len, + unsigned char *digest) +{ + EVP_MD_CTX *ctx; + unsigned int size = KEYCHAIN_HMAC_SHA1_HASH_SIZE; + + ctx = EVP_MD_CTX_new(); + EVP_DigestInit(ctx, EVP_sha1()); + EVP_DigestUpdate(ctx, mes, len); + EVP_DigestFinal(ctx, digest, &size); + EVP_MD_CTX_free(ctx); +} + +static void sha384_digest(unsigned char *mes, uint32_t len, + unsigned char *digest) +{ + EVP_MD_CTX *ctx; + unsigned int size = KEYCHAIN_HMAC_SHA384_HASH_SIZE; + + ctx = EVP_MD_CTX_new(); + EVP_DigestInit(ctx, EVP_sha384()); + EVP_DigestUpdate(ctx, mes, len); + EVP_DigestFinal(ctx, digest, &size); + EVP_MD_CTX_free(ctx); +} + +static void sha512_digest(unsigned char *mes, uint32_t len, + unsigned char *digest) +{ + EVP_MD_CTX *ctx; + unsigned int size = KEYCHAIN_HMAC_SHA512_HASH_SIZE; + + ctx = EVP_MD_CTX_new(); + EVP_DigestInit(ctx, EVP_sha512()); + EVP_DigestUpdate(ctx, mes, len); + EVP_DigestFinal(ctx, digest, &size); + EVP_MD_CTX_free(ctx); +} +#endif /* CRYPTO_OPENSSL */ + +static void ospf6_hash_hmac_sha_digest(enum keychain_hash_algo key, + unsigned char *mes, uint32_t len, + unsigned char *digest) +{ + if ((key < KEYCHAIN_ALGO_NULL) || (key > KEYCHAIN_ALGO_MAX)) + return; + + switch (key) { + case KEYCHAIN_ALGO_MD5: + md5_digest(mes, len, digest); + break; + case KEYCHAIN_ALGO_HMAC_SHA1: +#ifdef CRYPTO_OPENSSL + sha1_digest(mes, len, digest); +#endif + break; + case KEYCHAIN_ALGO_HMAC_SHA256: + sha256_digest(mes, len, digest); + break; + case KEYCHAIN_ALGO_HMAC_SHA384: +#ifdef CRYPTO_OPENSSL + sha384_digest(mes, len, digest); +#endif + break; + case KEYCHAIN_ALGO_HMAC_SHA512: +#ifdef CRYPTO_OPENSSL + sha512_digest(mes, len, digest); +#endif + break; + case KEYCHAIN_ALGO_NULL: + case KEYCHAIN_ALGO_MAX: + default: + /* no action */ + break; + } +} + +uint16_t ospf6_auth_len_get(struct ospf6_interface *oi) +{ + uint16_t at_len = 0; + char *keychain_name = NULL; + struct keychain *keychain = NULL; + struct key *key = NULL; + + if (CHECK_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_KEYCHAIN)) { + if (CHECK_FLAG(oi->at_data.flags, + OSPF6_AUTH_TRAILER_KEYCHAIN_VALID)) { + at_len = OSPF6_AUTH_HDR_MIN_SIZE + + keychain_get_hash_len(oi->at_data.hash_algo); + } else { + keychain_name = oi->at_data.keychain; + keychain = keychain_lookup(keychain_name); + if (keychain) { + key = key_lookup_for_send(keychain); + if (key && key->string + && key->hash_algo != KEYCHAIN_ALGO_NULL) { + at_len = OSPF6_AUTH_HDR_MIN_SIZE + + keychain_get_hash_len( + key->hash_algo); + } + } + } + } else if (CHECK_FLAG(oi->at_data.flags, + OSPF6_AUTH_TRAILER_MANUAL_KEY)) { + at_len = OSPF6_AUTH_HDR_MIN_SIZE + + keychain_get_hash_len(oi->at_data.hash_algo); + } + + return at_len; +} + +int ospf6_auth_validate_pkt(struct ospf6_interface *oi, unsigned int *pkt_len, + struct ospf6_header *oh, unsigned int *at_len, + unsigned int *lls_block_len) +{ + struct ospf6_hello *hello = NULL; + struct ospf6_dbdesc *dbdesc = NULL; + struct ospf6_neighbor *on = NULL; + struct ospf6_auth_hdr ospf6_auth_info; + uint16_t hdr_len = 0; + uint32_t oh_seqnum_h = 0; + uint32_t oh_seqnum_l = 0; + bool auth_present = false; + bool lls_present = false; + struct ospf6_lls_hdr *lls_hdr = NULL; + + on = ospf6_neighbor_lookup(oh->router_id, oi); + hdr_len = ntohs(oh->length); + if (*pkt_len < hdr_len) { + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_err("RECV[%s] Received incomplete %s packet", + oi->interface->name, + ospf6_message_type(oh->type)); + return OSPF6_AUTH_VALIDATE_FAILURE; + } else if (*pkt_len == hdr_len) { + if (oi->at_data.flags != 0) + return OSPF6_AUTH_VALIDATE_FAILURE; + /* No auth info to be considered. + */ + return OSPF6_AUTH_PROCESS_NORMAL; + } + + switch (oh->type) { + case OSPF6_MESSAGE_TYPE_HELLO: + hello = (struct ospf6_hello *)((uint8_t *)oh + + sizeof(struct ospf6_header)); + if (OSPF6_OPT_ISSET_EXT(hello->options, OSPF6_OPT_L)) + lls_present = true; + + if (OSPF6_OPT_ISSET_EXT(hello->options, OSPF6_OPT_AT)) + auth_present = true; + break; + case OSPF6_MESSAGE_TYPE_DBDESC: + dbdesc = (struct ospf6_dbdesc *)((uint8_t *)oh + + sizeof(struct ospf6_header)); + if (OSPF6_OPT_ISSET_EXT(dbdesc->options, OSPF6_OPT_L)) + lls_present = true; + + if (OSPF6_OPT_ISSET_EXT(dbdesc->options, OSPF6_OPT_AT)) + auth_present = true; + break; + case OSPF6_MESSAGE_TYPE_LSREQ: + case OSPF6_MESSAGE_TYPE_LSUPDATE: + case OSPF6_MESSAGE_TYPE_LSACK: + if (on) { + lls_present = on->lls_present; + auth_present = on->auth_present; + } + break; + default: + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_err("RECV[%s] : Wrong packet type %d", + oi->interface->name, oh->type); + return OSPF6_AUTH_VALIDATE_FAILURE; + } + + if ((oh->type == OSPF6_MESSAGE_TYPE_HELLO) + || (oh->type == OSPF6_MESSAGE_TYPE_DBDESC)) { + if (on) { + on->auth_present = auth_present; + on->lls_present = lls_present; + } + } + + if ((!auth_present && (oi->at_data.flags != 0)) + || (auth_present && (oi->at_data.flags == 0))) { + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_err("RECV[%s] : Auth option miss-match in %s pkt", + oi->interface->name, + ospf6_message_type(oh->type)); + return OSPF6_AUTH_VALIDATE_FAILURE; + } + + if (lls_present) { + lls_hdr = (struct ospf6_lls_hdr *)(oh + hdr_len); + *lls_block_len = ntohs(lls_hdr->length) * 4; + } + + if (*lls_block_len > (*pkt_len - hdr_len)) { + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_err("RECV[%s] : Wrong lls data in %s packet", + oi->interface->name, + ospf6_message_type(oh->type)); + return OSPF6_AUTH_VALIDATE_FAILURE; + } + + memset(&ospf6_auth_info, 0, sizeof(struct ospf6_auth_hdr)); + if ((*pkt_len - hdr_len - (*lls_block_len)) > sizeof(ospf6_auth_info)) { + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_err("RECV[%s] : Wrong auth data in %s packet", + oi->interface->name, + ospf6_message_type(oh->type)); + return OSPF6_AUTH_VALIDATE_FAILURE; + } + + memcpy(&ospf6_auth_info, ((uint8_t *)oh + hdr_len + (*lls_block_len)), + (*pkt_len - hdr_len - (*lls_block_len))); + if (ntohs(ospf6_auth_info.length) > OSPF6_AUTH_HDR_FULL) { + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_err("RECV[%s] : Wrong auth header length in %s", + oi->interface->name, + ospf6_message_type(oh->type)); + return OSPF6_AUTH_VALIDATE_FAILURE; + } + + /* after authentication header validation is done + * reduce the auth hdr size from the packet length + */ + *at_len = ntohs(ospf6_auth_info.length); + *pkt_len = (*pkt_len) - (*at_len) - (*lls_block_len); + + if (on) { + oh_seqnum_h = ntohl(ospf6_auth_info.seqnum_h); + oh_seqnum_l = ntohl(ospf6_auth_info.seqnum_l); + if ((oh_seqnum_h >= on->seqnum_h[oh->type]) + && (oh_seqnum_l > on->seqnum_l[oh->type])) { + /* valid sequence number received */ + on->seqnum_h[oh->type] = oh_seqnum_h; + on->seqnum_l[oh->type] = oh_seqnum_l; + } else { + if (IS_OSPF6_DEBUG_AUTH_RX) { + zlog_err( + "RECV[%s] : Nbr(%s) Auth Sequence number mismatch in %s ", + oi->interface->name, on->name, + ospf6_message_type(oh->type)); + zlog_err( + "nbr_seq_l %u, nbr_seq_h %u, hdr_seq_l %u, hdr_seq_h %u", + on->seqnum_l[oh->type], + on->seqnum_h[oh->type], oh_seqnum_l, + oh_seqnum_h); + } + + return OSPF6_AUTH_VALIDATE_FAILURE; + } + } + + return OSPF6_AUTH_VALIDATE_SUCCESS; +} + +/* Starting point of packet process function. */ +int ospf6_auth_check_digest(struct ospf6_header *oh, struct ospf6_interface *oi, + struct in6_addr *src, unsigned int lls_block_len) +{ + uint32_t hash_len = KEYCHAIN_MAX_HASH_SIZE; + unsigned char apad[hash_len]; + unsigned char temp_hash[hash_len]; + struct ospf6_auth_hdr *ospf6_auth; + uint32_t ipv6_addr_size = sizeof(struct in6_addr); + struct keychain *keychain = NULL; + struct key *key = NULL; + char *auth_str = NULL; + uint16_t auth_len = 0; + uint8_t hash_algo = 0; + uint16_t oh_len = ntohs(oh->length); + int ret = 0; + + if (oi->at_data.flags == 0) + return OSPF6_AUTH_PROCESS_NORMAL; + + ospf6_auth = (struct ospf6_auth_hdr *)((uint8_t *)oh + + (oh_len + lls_block_len)); + if (CHECK_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_KEYCHAIN)) { + keychain = keychain_lookup(oi->at_data.keychain); + if (!keychain) { + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_err( + "RECV[%s]: Keychain doesn't exist for %s", + oi->interface->name, + ospf6_message_type(oh->type)); + return OSPF6_AUTH_VALIDATE_FAILURE; + } + + key = key_lookup_for_accept(keychain, ntohs(ospf6_auth->id)); + if (!key) { + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_err("RECV[%s]: Auth, Invalid SA for %s", + oi->interface->name, + ospf6_message_type(oh->type)); + return OSPF6_AUTH_VALIDATE_FAILURE; + } + + if (key && key->string + && key->hash_algo != KEYCHAIN_ALGO_NULL) { + auth_str = key->string; + hash_algo = key->hash_algo; + } else { + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_err( + "RECV[%s]: Incomplete keychain config for %s", + oi->interface->name, + ospf6_message_type(oh->type)); + return OSPF6_AUTH_VALIDATE_FAILURE; + } + } else if (CHECK_FLAG(oi->at_data.flags, + OSPF6_AUTH_TRAILER_MANUAL_KEY)) { + auth_str = oi->at_data.auth_key; + hash_algo = oi->at_data.hash_algo; + } + + if (!auth_str) + return OSPF6_AUTH_VALIDATE_FAILURE; + + hash_len = keychain_get_hash_len(hash_algo); + memset(apad, 0, sizeof(apad)); + memset(temp_hash, 0, sizeof(temp_hash)); + + /* start digest verification */ + memcpy(apad, src, ipv6_addr_size); + memcpy(apad + ipv6_addr_size, ospf6_hash_apad_max, + (hash_len - ipv6_addr_size)); + + auth_len = ntohs(ospf6_auth->length); + + memcpy(temp_hash, ospf6_auth->data, hash_len); + memcpy(ospf6_auth->data, apad, hash_len); + + ospf6_auth_update_digest(oi, oh, ospf6_auth, auth_str, + (oh_len + auth_len + lls_block_len), + hash_algo); + +#ifdef CRYPTO_OPENSSL + ret = CRYPTO_memcmp(temp_hash, ospf6_auth->data, hash_len); +#else + ret = memcmp(temp_hash, ospf6_auth->data, hash_len); +#endif + if (ret == 0) + return OSPF6_AUTH_VALIDATE_SUCCESS; + + return OSPF6_AUTH_VALIDATE_FAILURE; +} + +void ospf6_auth_digest_send(struct in6_addr *src, struct ospf6_interface *oi, + struct ospf6_header *oh, uint16_t auth_len, + uint32_t pkt_len) +{ + struct ospf6_auth_hdr *ospf6_auth; + char *keychain_name = NULL; + struct keychain *keychain = NULL; + struct key *key = NULL; + char *auth_str = NULL; + uint16_t key_id = 0; + enum keychain_hash_algo hash_algo = KEYCHAIN_ALGO_NULL; + uint32_t hash_len = KEYCHAIN_MAX_HASH_SIZE; + unsigned char apad[hash_len]; + int ipv6_addr_size = sizeof(struct in6_addr); + struct ospf6 *ospf6 = NULL; + + if (CHECK_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_KEYCHAIN)) { + if (CHECK_FLAG(oi->at_data.flags, + OSPF6_AUTH_TRAILER_KEYCHAIN_VALID)) { + auth_str = oi->at_data.auth_key; + hash_algo = oi->at_data.hash_algo; + key_id = oi->at_data.key_id; + } else { + keychain_name = oi->at_data.keychain; + keychain = keychain_lookup(keychain_name); + if (keychain) { + key = key_lookup_for_send(keychain); + if (key && key->string + && key->hash_algo != KEYCHAIN_ALGO_NULL) { + auth_str = key->string; + hash_algo = key->hash_algo; + key_id = key->index; + } + } + } + } else if (CHECK_FLAG(oi->at_data.flags, + OSPF6_AUTH_TRAILER_MANUAL_KEY)) { + auth_str = oi->at_data.auth_key; + hash_algo = oi->at_data.hash_algo; + key_id = oi->at_data.key_id; + } else { + if (IS_OSPF6_DEBUG_AUTH_TX) + zlog_warn("SEND[%s]: Authentication not configured for %s", + oi->interface->name, + ospf6_message_type(oh->type)); + return; + } + + if (!auth_str) { + if (IS_OSPF6_DEBUG_AUTH_TX) + zlog_warn("SEND[%s]: Authentication key is not configured for %s", + oi->interface->name, + ospf6_message_type(oh->type)); + return; + } + + hash_len = keychain_get_hash_len(hash_algo); + if (oi->area && oi->area->ospf6) + ospf6 = oi->area->ospf6; + else + return; + + ospf6->seqnum_l++; + if (ospf6->seqnum_l == 0xFFFFFFFF) { + ospf6->seqnum_h++; + ospf6->seqnum_l = 0; + ospf6_auth_seqno_nvm_update(ospf6); + } + + /* Key must be reset. which is not handled as of now. */ + if ((ospf6->seqnum_l == 0xFFFFFFFF) + && (ospf6->seqnum_h == 0xFFFFFFFF)) { + ospf6->seqnum_l = 0; + ospf6->seqnum_h = 0; + zlog_err( + "Both Higher and Lower sequence number has wrapped. Need to reset the key"); + } + + memset(apad, 0, sizeof(apad)); + + if (src) + memcpy(apad, src, ipv6_addr_size); + + memcpy(apad + ipv6_addr_size, ospf6_hash_apad_max, + (hash_len - ipv6_addr_size)); + + ospf6_auth = + (struct ospf6_auth_hdr *)((uint8_t *)oh + ntohs(oh->length)); + ospf6_auth->type = htons(OSPF6_AUTHENTICATION_CRYPTOGRAPHIC); + ospf6_auth->length = htons(auth_len); + ospf6_auth->reserved = 0; + ospf6_auth->id = htons(key_id); + ospf6_auth->seqnum_h = htonl(ospf6->seqnum_h); + ospf6_auth->seqnum_l = htonl(ospf6->seqnum_l); + memcpy(ospf6_auth->data, apad, hash_len); + + ospf6_auth_update_digest(oi, oh, ospf6_auth, auth_str, pkt_len, + hash_algo); + + /* There is a optimisation that is done to ensure that + * for every packet flow keychain lib API are called + * only once and the result are stored in oi->at_data. + * So, After processing the flow it is reset back here. + */ + if (CHECK_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_KEYCHAIN_VALID)) { + oi->at_data.hash_algo = KEYCHAIN_ALGO_NULL; + if (oi->at_data.auth_key) { + XFREE(MTYPE_OSPF6_AUTH_MANUAL_KEY, + oi->at_data.auth_key); + oi->at_data.auth_key = NULL; + } + + oi->at_data.key_id = 0; + UNSET_FLAG(oi->at_data.flags, + OSPF6_AUTH_TRAILER_KEYCHAIN_VALID); + } +} + +void ospf6_auth_update_digest(struct ospf6_interface *oi, + struct ospf6_header *oh, + struct ospf6_auth_hdr *ospf6_auth, char *auth_str, + uint32_t pkt_len, enum keychain_hash_algo algo) +{ + static const uint16_t cpid = 1; + uint32_t hash_len = keychain_get_hash_len(algo); + uint32_t block_s = keychain_get_block_size(algo); + uint32_t k_len = strlen(auth_str); + uint32_t ks_len = strlen(auth_str) + sizeof(cpid); + unsigned char ipad[block_s]; + unsigned char opad[block_s]; + unsigned char ko[block_s], ks[ks_len], tmp[hash_len]; + unsigned char *first = NULL; + unsigned char *second = NULL; + unsigned char first_mes[block_s + pkt_len]; + unsigned char second_mes[block_s + pkt_len]; + unsigned char first_hash[hash_len]; + unsigned char second_hash[hash_len]; + + memset(ko, 0, sizeof(ko)); + memcpy(ks, auth_str, k_len); + memcpy(ks + k_len, &cpid, sizeof(cpid)); + if (ks_len > hash_len) { + ospf6_hash_hmac_sha_digest(algo, ks, ks_len, tmp); + memcpy(ko, tmp, hash_len); + } else + memcpy(ko, ks, ks_len); + + memcpy(ipad, ospf6_hash_ipad_max, block_s); + memcpy(opad, ospf6_hash_opad_max, block_s); + + first = ospf6_hash_message_xor((unsigned char *)&ipad, ko, block_s); + second = ospf6_hash_message_xor((unsigned char *)&opad, ko, block_s); + + memcpy(first_mes, first, block_s); + memcpy(first_mes + block_s, oh, pkt_len); + + ospf6_hash_hmac_sha_digest(algo, first_mes, (block_s + pkt_len), + first_hash); + + memcpy(second_mes, second, block_s); + memcpy(second_mes + block_s, first_hash, hash_len); + + ospf6_hash_hmac_sha_digest(algo, second_mes, (block_s + hash_len), + second_hash); + + memcpy(ospf6_auth->data, second_hash, hash_len); + XFREE(MTYPE_OSPF6_AUTH_HASH_XOR, first); + XFREE(MTYPE_OSPF6_AUTH_HASH_XOR, second); +} + +DEFUN (debug_ospf6_auth, + debug_ospf6_auth_cmd, + "debug ospf6 authentication [<tx|rx>]", + DEBUG_STR + OSPF6_STR + "debug OSPF6 authentication\n" + "debug authentication tx\n" + "debug authentication rx\n") +{ + int auth_opt_idx = 3; + + if (argc == 4) { + if (!strncmp(argv[auth_opt_idx]->arg, "t", 1)) + OSPF6_DEBUG_AUTH_TX_ON(); + else if (!strncmp(argv[auth_opt_idx]->arg, "r", 1)) + OSPF6_DEBUG_AUTH_RX_ON(); + } else { + OSPF6_DEBUG_AUTH_TX_ON(); + OSPF6_DEBUG_AUTH_RX_ON(); + } + + return CMD_SUCCESS; +} + +DEFUN (no_debug_ospf6_auth, + no_debug_ospf6_auth_cmd, + "no debug ospf6 authentication [<tx|rx>]", + NO_STR + DEBUG_STR + OSPF6_STR + "debug OSPF6 authentication\n" + "debug authentication tx\n" + "debug authentication rx\n") +{ + int auth_opt_idx = 3; + + if (argc == 5) { + if (!strncmp(argv[auth_opt_idx]->arg, "t", 1)) + OSPF6_DEBUG_AUTH_TX_OFF(); + else if (!strncmp(argv[auth_opt_idx]->arg, "r", 1)) + OSPF6_DEBUG_AUTH_RX_OFF(); + } else { + OSPF6_DEBUG_AUTH_TX_OFF(); + OSPF6_DEBUG_AUTH_RX_OFF(); + } + + return CMD_SUCCESS; +} + +int config_write_ospf6_debug_auth(struct vty *vty) +{ + if (IS_OSPF6_DEBUG_AUTH_TX) + vty_out(vty, "debug ospf6 authentication tx\n"); + if (IS_OSPF6_DEBUG_AUTH_RX) + vty_out(vty, "debug ospf6 authentication rx\n"); + return 0; +} + +void install_element_ospf6_debug_auth(void) +{ + install_element(ENABLE_NODE, &debug_ospf6_auth_cmd); + install_element(ENABLE_NODE, &no_debug_ospf6_auth_cmd); + install_element(CONFIG_NODE, &debug_ospf6_auth_cmd); + install_element(CONFIG_NODE, &no_debug_ospf6_auth_cmd); +} + +/* Clear the specified interface structure */ +static void ospf6_intf_auth_clear(struct vty *vty, struct interface *ifp) +{ + struct ospf6_interface *oi; + + if (!if_is_operative(ifp)) + return; + + if (ifp->info == NULL) + return; + + oi = (struct ospf6_interface *)ifp->info; + + if (IS_OSPF6_DEBUG_INTERFACE) + zlog_debug( + "Interface %s: clear authentication rx/tx drop counters", + ifp->name); + + /* Reset the interface rx/tx drop counters */ + oi->at_data.tx_drop = 0; + oi->at_data.rx_drop = 0; +} + +/* Clear interface */ +DEFUN(clear_ipv6_ospf6_intf_auth, clear_ipv6_ospf6_intf_auth_cmd, + "clear ipv6 ospf6 [vrf VRF] auth-counters interface [IFNAME]", + CLEAR_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR + "authentication rx/tx drop counters\n" INTERFACE_STR IFNAME_STR) +{ + int idx_ifname = 0; + int idx_vrf = 0; + struct interface *ifp; + struct listnode *node; + struct ospf6 *ospf6 = NULL; + char *vrf_name = NULL; + vrf_id_t vrf_id = VRF_DEFAULT; + struct vrf *vrf = NULL; + + if (argv_find(argv, argc, "vrf", &idx_vrf)) + vrf_name = argv[idx_vrf + 1]->arg; + + if (vrf_name && strmatch(vrf_name, VRF_DEFAULT_NAME)) + vrf_name = NULL; + + if (vrf_name) { + vrf = vrf_lookup_by_name(vrf_name); + if (vrf) + vrf_id = vrf->vrf_id; + } + + if (!argv_find(argv, argc, "IFNAME", &idx_ifname)) { + /* Clear all the ospfv3 interfaces auth data. */ + for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) { + if (vrf_id != ospf6->vrf_id) + continue; + + if (!vrf) + vrf = vrf_lookup_by_id(ospf6->vrf_id); + FOR_ALL_INTERFACES (vrf, ifp) + ospf6_intf_auth_clear(vty, ifp); + } + } else { + /* Interface name is specified. */ + ifp = if_lookup_by_name(argv[idx_ifname]->arg, vrf_id); + if (ifp == NULL) + vty_out(vty, "No such interface name\n"); + else + ospf6_intf_auth_clear(vty, ifp); + } + + return CMD_SUCCESS; +} + +void install_element_ospf6_clear_intf_auth(void) +{ + install_element(ENABLE_NODE, &clear_ipv6_ospf6_intf_auth_cmd); +} + +enum ospf6_auth_err ospf6_auth_nvm_file_exist(void) +{ + struct stat buffer; + int exist; + + exist = stat(OSPF6_AUTH_SEQ_NUM_FILE, &buffer); + if (exist == 0) + return OSPF6_AUTH_FILE_EXIST; + else + return OSPF6_AUTH_FILE_DO_NOT_EXIST; +} + +/* + * Record in non-volatile memory the given ospf6 process, + * authentication trailer higher order sequence number. + */ +void ospf6_auth_seqno_nvm_update(struct ospf6 *ospf6) +{ + const char *inst_name; + json_object *json; + json_object *json_instances; + json_object *json_instance; + + zlog_err("Higher order sequence number %d update for %s process", + ospf6->seqnum_h, ospf6->name); + + inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME; + + json = json_object_from_file((char *)OSPF6_AUTH_SEQ_NUM_FILE); + if (json == NULL) + json = json_object_new_object(); + + json_object_object_get_ex(json, "instances", &json_instances); + if (!json_instances) { + json_instances = json_object_new_object(); + json_object_object_add(json, "instances", json_instances); + } + + json_object_object_get_ex(json_instances, inst_name, &json_instance); + if (!json_instance) { + json_instance = json_object_new_object(); + json_object_object_add(json_instances, inst_name, + json_instance); + } + + /* + * Record higher order sequence number in non volatile memory. + */ + json_object_int_add(json_instance, "sequence_number", ospf6->seqnum_h); + + json_object_to_file_ext((char *)OSPF6_AUTH_SEQ_NUM_FILE, json, + JSON_C_TO_STRING_PRETTY); + json_object_free(json); +} + +/* + * Delete authentication sequence number for a given OSPF6 process + * from non-volatile memory. + */ +void ospf6_auth_seqno_nvm_delete(struct ospf6 *ospf6) +{ + const char *inst_name; + json_object *json; + json_object *json_instances; + + zlog_err("Higher order sequence number delete for %s process", + ospf6->name); + + inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME; + + json = json_object_from_file((char *)OSPF6_AUTH_SEQ_NUM_FILE); + if (json == NULL) + json = json_object_new_object(); + + json_object_object_get_ex(json, "instances", &json_instances); + if (!json_instances) { + json_instances = json_object_new_object(); + json_object_object_add(json, "instances", json_instances); + } + + json_object_object_del(json_instances, inst_name); + + json_object_to_file_ext((char *)OSPF6_AUTH_SEQ_NUM_FILE, json, + JSON_C_TO_STRING_PRETTY); + json_object_free(json); +} + + +/* + * Fetch from non-volatile memory the stored ospf6 process + * authentication sequence number. + */ +void ospf6_auth_seqno_nvm_read(struct ospf6 *ospf6) +{ + const char *inst_name; + json_object *json; + json_object *json_instances; + json_object *json_instance; + json_object *json_seqnum; + + inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME; + + json = json_object_from_file((char *)OSPF6_AUTH_SEQ_NUM_FILE); + if (json == NULL) + json = json_object_new_object(); + + json_object_object_get_ex(json, "instances", &json_instances); + if (!json_instances) { + json_instances = json_object_new_object(); + json_object_object_add(json, "instances", json_instances); + } + + json_object_object_get_ex(json_instances, inst_name, &json_instance); + if (!json_instance) { + json_instance = json_object_new_object(); + json_object_object_add(json_instances, inst_name, + json_instance); + } + + json_object_object_get_ex(json_instance, "sequence_number", + &json_seqnum); + ospf6->seqnum_h = json_object_get_int(json_seqnum); + + zlog_err("Higher order sequence number %d read for %s process %s", + ospf6->seqnum_h, ospf6->name, strerror(errno)); + + json_object_object_del(json_instances, inst_name); + json_object_to_file_ext((char *)OSPF6_AUTH_SEQ_NUM_FILE, json, + JSON_C_TO_STRING_PRETTY); + json_object_free(json); +} diff --git a/ospf6d/ospf6_auth_trailer.h b/ospf6d/ospf6_auth_trailer.h new file mode 100644 index 0000000000..dea4a6e168 --- /dev/null +++ b/ospf6d/ospf6_auth_trailer.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2021 Abhinay Ramesh + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __OSPF6_AUTH_TRAILER_H__ +#define __OSPF6_AUTH_TRAILER_H__ + +#include "lib/keychain.h" +#include "ospf6_message.h" + +#define OSPF6_AUTH_HDR_MIN_SIZE 16 +#define OSPF6_AUTH_HDR_FULL KEYCHAIN_MAX_HASH_SIZE + OSPF6_AUTH_HDR_MIN_SIZE + +#define OSPF6_AUTHENTICATION_NULL 0 +#define OSPF6_AUTHENTICATION_CRYPTOGRAPHIC 1 + +/* Auth debug options */ +extern unsigned char conf_debug_ospf6_auth[2]; + +#define OSPF6_AUTH_TX 0 +#define OSPF6_AUTH_RX 1 +#define OSPF6_DEBUG_AUTH_TX_ON() (conf_debug_ospf6_auth[OSPF6_AUTH_TX] = 1) +#define OSPF6_DEBUG_AUTH_TX_OFF() (conf_debug_ospf6_auth[OSPF6_AUTH_TX] = 0) +#define OSPF6_DEBUG_AUTH_RX_ON() (conf_debug_ospf6_auth[OSPF6_AUTH_RX] = 1) +#define OSPF6_DEBUG_AUTH_RX_OFF() (conf_debug_ospf6_auth[OSPF6_AUTH_RX] = 0) +#define IS_OSPF6_DEBUG_AUTH_TX (conf_debug_ospf6_auth[OSPF6_AUTH_TX]) +#define IS_OSPF6_DEBUG_AUTH_RX (conf_debug_ospf6_auth[OSPF6_AUTH_RX]) + +#define OSPF6_AUTH_TRAILER_KEYCHAIN (1 << 0) +#define OSPF6_AUTH_TRAILER_MANUAL_KEY (1 << 1) +#define OSPF6_AUTH_TRAILER_KEYCHAIN_VALID (1 << 2) + +/* According to sesion 4.1 of RFC7166 defining the trailer struct */ +struct ospf6_auth_hdr { + uint16_t type; + uint16_t length; + uint16_t reserved; + uint16_t id; + uint32_t seqnum_h; + uint32_t seqnum_l; + unsigned char data[KEYCHAIN_MAX_HASH_SIZE]; +}; + +enum ospf6_auth_err { + OSPF6_AUTH_VALIDATE_SUCCESS = 0, + OSPF6_AUTH_VALIDATE_FAILURE, + OSPF6_AUTH_PROCESS_NORMAL, + OSPF6_AUTH_FILE_EXIST, + OSPF6_AUTH_FILE_DO_NOT_EXIST +}; + +void ospf6_auth_hdr_dump_send(struct ospf6_header *ospfh, uint16_t length); +void ospf6_auth_hdr_dump_recv(struct ospf6_header *ospfh, uint16_t length, + unsigned int lls_len); +unsigned char *ospf6_hash_message_xor(unsigned char *mes1, unsigned char *mes2, + uint32_t len); +uint16_t ospf6_auth_len_get(struct ospf6_interface *oi); +int ospf6_auth_validate_pkt(struct ospf6_interface *oi, unsigned int *pkt_len, + struct ospf6_header *oh, unsigned int *at_len, + unsigned int *lls_block_len); +int ospf6_auth_check_digest(struct ospf6_header *oh, struct ospf6_interface *oi, + struct in6_addr *src, unsigned int lls_len); +void ospf6_auth_update_digest(struct ospf6_interface *oi, + struct ospf6_header *oh, + struct ospf6_auth_hdr *ospf6_auth, char *auth_str, + uint32_t pkt_len, enum keychain_hash_algo algo); +void ospf6_auth_digest_send(struct in6_addr *src, struct ospf6_interface *oi, + struct ospf6_header *oh, uint16_t auth_len, + uint32_t pkt_len); +void install_element_ospf6_debug_auth(void); +int config_write_ospf6_debug_auth(struct vty *vty); +void install_element_ospf6_clear_intf_auth(void); +enum ospf6_auth_err ospf6_auth_nvm_file_exist(void); +void ospf6_auth_seqno_nvm_update(struct ospf6 *ospf6); +void ospf6_auth_seqno_nvm_delete(struct ospf6 *ospf6); +void ospf6_auth_seqno_nvm_read(struct ospf6 *ospf6); +#endif /* __OSPF6_AUTH_TRAILER_H__ */ diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 0d9f15d08f..f39d208bb5 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -46,8 +46,13 @@ #include "ospf6_zebra.h" #include "ospf6_gr.h" #include "lib/json.h" +#include "ospf6_proto.h" +#include "lib/keychain.h" +#include "ospf6_auth_trailer.h" DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_IF, "OSPF6 interface"); +DEFINE_MTYPE(OSPF6D, OSPF6_AUTH_KEYCHAIN, "OSPF6 auth keychain"); +DEFINE_MTYPE(OSPF6D, OSPF6_AUTH_MANUAL_KEY, "OSPF6 auth key"); DEFINE_MTYPE_STATIC(OSPF6D, CFG_PLIST_NAME, "configured prefix list names"); DEFINE_QOBJ_TYPE(ospf6_interface); DEFINE_HOOK(ospf6_interface_change, @@ -252,6 +257,8 @@ struct ospf6_interface *ospf6_interface_create(struct interface *ifp) /* Compute cost. */ oi->cost = ospf6_interface_get_cost(oi); + oi->at_data.flags = 0; + return oi; } @@ -990,6 +997,7 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp, struct ospf6_lsa *lsa, *lsanext; json_object *json_arr; json_object *json_addr; + struct json_object *json_auth = NULL; default_iftype = ospf6_default_iftype(ifp); @@ -1238,6 +1246,48 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp, } } + json_auth = json_object_new_object(); + if (oi->at_data.flags != 0) { + if (use_json) { + if (CHECK_FLAG(oi->at_data.flags, + OSPF6_AUTH_TRAILER_KEYCHAIN)) { + json_object_string_add(json_auth, "authType", + "keychain"); + json_object_string_add(json_auth, + "keychainName", + oi->at_data.keychain); + } else if (CHECK_FLAG(oi->at_data.flags, + OSPF6_AUTH_TRAILER_MANUAL_KEY)) + json_object_string_add(json_auth, "authType", + "manualkey"); + json_object_int_add(json_auth, "txPktDrop", + oi->at_data.tx_drop); + json_object_int_add(json_auth, "rxPktDrop", + oi->at_data.rx_drop); + } else { + if (CHECK_FLAG(oi->at_data.flags, + OSPF6_AUTH_TRAILER_KEYCHAIN)) + vty_out(vty, + " Authentication Trailer is enabled with key-chain %s\n", + oi->at_data.keychain); + else if (CHECK_FLAG(oi->at_data.flags, + OSPF6_AUTH_TRAILER_MANUAL_KEY)) + vty_out(vty, + " Authentication trailer is enabled with manual key\n"); + vty_out(vty, + " Packet drop Tx %u, Packet drop Rx %u\n", + oi->at_data.tx_drop, oi->at_data.rx_drop); + } + } else { + if (use_json) + json_object_string_add(json_auth, "authType", "NULL"); + else + vty_out(vty, " Authentication Trailer is disabled\n"); + } + + if (use_json) + json_object_object_add(json_obj, "authInfo", json_auth); + return 0; } @@ -2577,6 +2627,7 @@ static int config_write_ospf6_interface(struct vty *vty, struct vrf *vrf) ospf6_bfd_write_config(vty, oi); + ospf6_auth_write_config(vty, &oi->at_data); if_vty_config_end(vty); } return 0; @@ -2815,3 +2866,195 @@ void install_element_ospf6_debug_interface(void) install_element(CONFIG_NODE, &debug_ospf6_interface_cmd); install_element(CONFIG_NODE, &no_debug_ospf6_interface_cmd); } + +void ospf6_auth_write_config(struct vty *vty, struct ospf6_auth_data *at_data) +{ + if (CHECK_FLAG(at_data->flags, OSPF6_AUTH_TRAILER_KEYCHAIN)) + vty_out(vty, " ipv6 ospf6 authentication keychain %s\n", + at_data->keychain); + else if (CHECK_FLAG(at_data->flags, OSPF6_AUTH_TRAILER_MANUAL_KEY)) + vty_out(vty, + " ipv6 ospf6 authentication key-id %d hash-algo %s key %s\n", + at_data->key_id, + keychain_get_algo_name_by_id(at_data->hash_algo), + at_data->auth_key); +} + +DEFUN(ipv6_ospf6_intf_auth_trailer_keychain, + ipv6_ospf6_intf_auth_trailer_keychain_cmd, + "ipv6 ospf6 authentication keychain KEYCHAIN_NAME", + IP6_STR OSPF6_STR + "Enable authentication on this interface\n" + "Keychain\n" + "Keychain name\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + int keychain_idx = 4; + struct ospf6_interface *oi; + + oi = (struct ospf6_interface *)ifp->info; + if (oi == NULL) + oi = ospf6_interface_create(ifp); + + assert(oi); + if (CHECK_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_MANUAL_KEY)) { + vty_out(vty, + "Manual key configured, unconfigure it before configuring key chain\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + SET_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_KEYCHAIN); + if (oi->at_data.keychain) + XFREE(MTYPE_OSPF6_AUTH_KEYCHAIN, oi->at_data.keychain); + + oi->at_data.keychain = + XSTRDUP(MTYPE_OSPF6_AUTH_KEYCHAIN, argv[keychain_idx]->arg); + + return CMD_SUCCESS; +} + +DEFUN(no_ipv6_ospf6_intf_auth_trailer_keychain, + no_ipv6_ospf6_intf_auth_trailer_keychain_cmd, + "no ipv6 ospf6 authentication keychain [KEYCHAIN_NAME]", + NO_STR IP6_STR OSPF6_STR + "Enable authentication on this interface\n" + "Keychain\n" + "Keychain name\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct ospf6_interface *oi; + + oi = (struct ospf6_interface *)ifp->info; + if (oi == NULL) + oi = ospf6_interface_create(ifp); + + assert(oi); + if (!CHECK_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_KEYCHAIN)) + return CMD_SUCCESS; + + if (oi->at_data.keychain) { + oi->at_data.flags = 0; + XFREE(MTYPE_OSPF6_AUTH_KEYCHAIN, oi->at_data.keychain); + oi->at_data.keychain = NULL; + } + + return CMD_SUCCESS; +} + +DEFUN(ipv6_ospf6_intf_auth_trailer_key, ipv6_ospf6_intf_auth_trailer_key_cmd, + "ipv6 ospf6 authentication key-id (1-65535) hash-algo " + "<md5|hmac-sha-1|hmac-sha-256|hmac-sha-384|hmac-sha-512> " + "key WORD", + IP6_STR OSPF6_STR + "Authentication\n" + "Key ID\n" + "Key ID value\n" + "Cryptographic-algorithm\n" + "Use MD5 algorithm\n" + "Use HMAC-SHA-1 algorithm\n" + "Use HMAC-SHA-256 algorithm\n" + "Use HMAC-SHA-384 algorithm\n" + "Use HMAC-SHA-512 algorithm\n" + "Password\n" + "Password string (key)\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + int key_id_idx = 4; + int hash_algo_idx = 6; + int password_idx = 8; + struct ospf6_interface *oi; + uint8_t hash_algo = KEYCHAIN_ALGO_NULL; + + oi = (struct ospf6_interface *)ifp->info; + if (oi == NULL) + oi = ospf6_interface_create(ifp); + + assert(oi); + if (CHECK_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_KEYCHAIN)) { + vty_out(vty, + "key chain configured, unconfigure it before configuring manual key\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + hash_algo = keychain_get_algo_id_by_name(argv[hash_algo_idx]->arg); +#ifndef CRYPTO_OPENSSL + if (hash_algo == KEYCHAIN_ALGO_NULL) { + vty_out(vty, + "Hash algorithm not supported, compile with --with-crypto=openssl\n"); + return CMD_WARNING_CONFIG_FAILED; + } +#endif /* CRYPTO_OPENSSL */ + + SET_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_MANUAL_KEY); + oi->at_data.hash_algo = hash_algo; + oi->at_data.key_id = (uint16_t)strtol(argv[key_id_idx]->arg, NULL, 10); + if (oi->at_data.auth_key) + XFREE(MTYPE_OSPF6_AUTH_MANUAL_KEY, oi->at_data.auth_key); + oi->at_data.auth_key = + XSTRDUP(MTYPE_OSPF6_AUTH_MANUAL_KEY, argv[password_idx]->arg); + + return CMD_SUCCESS; +} + +DEFUN(no_ipv6_ospf6_intf_auth_trailer_key, + no_ipv6_ospf6_intf_auth_trailer_key_cmd, + "no ipv6 ospf6 authentication key-id [(1-65535) hash-algo " + "<md5|hmac-sha-1|hmac-sha-256|hmac-sha-384|hmac-sha-512> " + "key WORD]", + NO_STR IP6_STR OSPF6_STR + "Authentication\n" + "Key ID\n" + "Key ID value\n" + "Cryptographic-algorithm\n" + "Use MD5 algorithm\n" + "Use HMAC-SHA-1 algorithm\n" + "Use HMAC-SHA-256 algorithm\n" + "Use HMAC-SHA-384 algorithm\n" + "Use HMAC-SHA-512 algorithm\n" + "Password\n" + "Password string (key)\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct ospf6_interface *oi; +#ifndef CRYPTO_OPENSSL + int hash_algo_idx = 7; + uint8_t hash_algo = KEYCHAIN_ALGO_NULL; +#endif /* CRYPTO_OPENSSL */ + + oi = (struct ospf6_interface *)ifp->info; + if (oi == NULL) + oi = ospf6_interface_create(ifp); + + assert(oi); + if (!CHECK_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_MANUAL_KEY)) + return CMD_SUCCESS; + +#ifndef CRYPTO_OPENSSL + hash_algo = keychain_get_algo_id_by_name(argv[hash_algo_idx]->arg); + if (hash_algo == KEYCHAIN_ALGO_NULL) { + vty_out(vty, + "Hash algorithm not supported, compile with --with-crypto=openssl\n"); + return CMD_WARNING_CONFIG_FAILED; + } +#endif /* CRYPTO_OPENSSL */ + + if (oi->at_data.auth_key) { + oi->at_data.flags = 0; + XFREE(MTYPE_OSPF6_AUTH_MANUAL_KEY, oi->at_data.auth_key); + oi->at_data.auth_key = NULL; + } + + return CMD_SUCCESS; +} + +void ospf6_interface_auth_trailer_cmd_init(void) +{ + /*Install OSPF6 auth trailer commands at interface level */ + install_element(INTERFACE_NODE, + &ipv6_ospf6_intf_auth_trailer_keychain_cmd); + install_element(INTERFACE_NODE, + &no_ipv6_ospf6_intf_auth_trailer_keychain_cmd); + install_element(INTERFACE_NODE, &ipv6_ospf6_intf_auth_trailer_key_cmd); + install_element(INTERFACE_NODE, + &no_ipv6_ospf6_intf_auth_trailer_key_cmd); +} diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h index ee24b989bd..59e4888a5f 100644 --- a/ospf6d/ospf6_interface.h +++ b/ospf6d/ospf6_interface.h @@ -24,6 +24,9 @@ #include "qobj.h" #include "hook.h" #include "if.h" +#include "ospf6d.h" + +DECLARE_MTYPE(OSPF6_AUTH_MANUAL_KEY); /* Debug option */ extern unsigned char conf_debug_ospf6_interface; @@ -31,6 +34,21 @@ extern unsigned char conf_debug_ospf6_interface; #define OSPF6_DEBUG_INTERFACE_OFF() (conf_debug_ospf6_interface = 0) #define IS_OSPF6_DEBUG_INTERFACE (conf_debug_ospf6_interface) +struct ospf6_auth_data { + /* config data */ + uint8_t hash_algo; /* hash algorithm type */ + uint16_t key_id; /* key-id used as SA in auth packet */ + char *auth_key; /* Auth key */ + char *keychain; /* keychain name */ + + /* operational data */ + uint8_t flags; /* Flags related to auth config */ + + /* Counters and Statistics */ + uint32_t tx_drop; /* Pkt drop due to auth fail while sending */ + uint32_t rx_drop; /* Pkt drop due to auth fail while reading */ +}; + /* Interface structure */ struct ospf6_interface { /* IF info from zebra */ @@ -95,6 +113,9 @@ struct ospf6_interface { /* MTU mismatch check */ uint8_t mtu_ignore; + /* Authentication trailer related config */ + struct ospf6_auth_data at_data; + /* Decision of DR Election */ in_addr_t drouter; in_addr_t bdrouter; @@ -221,6 +242,9 @@ extern void install_element_ospf6_debug_interface(void); extern int ospf6_interface_neighbor_count(struct ospf6_interface *oi); extern uint8_t dr_election(struct ospf6_interface *oi); +extern void ospf6_interface_auth_trailer_cmd_init(void); +extern void ospf6_auth_write_config(struct vty *vty, + struct ospf6_auth_data *at_data); DECLARE_HOOK(ospf6_interface_change, (struct ospf6_interface * oi, int state, int old_state), (oi, state, old_state)); diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index 6626b4bed5..da5cad0537 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -2148,7 +2148,7 @@ static void ospf6_brouter_debug_print(struct ospf6_route *brouter) char installed[64], changed[64]; struct timeval now, res; char id[16], adv_router[16]; - char capa[16], options[16]; + char capa[16], options[32]; brouter_id = ADV_ROUTER_IN_PREFIX(&brouter->prefix); inet_ntop(AF_INET, &brouter_id, brouter_name, sizeof(brouter_name)); diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c index 165a764c38..120f307adc 100644 --- a/ospf6d/ospf6_main.c +++ b/ospf6d/ospf6_main.c @@ -20,6 +20,7 @@ #include <zebra.h> #include <lib/version.h> +#include <lib/keychain.h> #include <stdlib.h> #include "getopt.h" @@ -223,6 +224,7 @@ int main(int argc, char *argv[], char *envp[]) /* thread master */ master = om6->master; + keychain_init(); ospf6_vrf_init(); access_list_init(); prefix_list_init(); diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 352cb137ed..7ebfdd26e1 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -27,6 +27,7 @@ #include "thread.h" #include "linklist.h" #include "lib_errors.h" +#include "checksum.h" #include "ospf6_proto.h" #include "ospf6_lsa.h" @@ -48,19 +49,34 @@ #include "ospf6d.h" #include "ospf6_gr.h" #include <netinet/ip6.h> +#include "lib/libospf.h" +#include "lib/keychain.h" +#include "ospf6_auth_trailer.h" DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_MESSAGE, "OSPF6 message"); DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_PACKET, "OSPF6 packet"); DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_FIFO, "OSPF6 FIFO queue"); unsigned char conf_debug_ospf6_message[6] = {0x03, 0, 0, 0, 0, 0}; -static const struct message ospf6_message_type_str[] = { - {OSPF6_MESSAGE_TYPE_HELLO, "Hello"}, - {OSPF6_MESSAGE_TYPE_DBDESC, "DbDesc"}, - {OSPF6_MESSAGE_TYPE_LSREQ, "LSReq"}, - {OSPF6_MESSAGE_TYPE_LSUPDATE, "LSUpdate"}, - {OSPF6_MESSAGE_TYPE_LSACK, "LSAck"}, - {0}}; + +const char *ospf6_message_type(int type) +{ + switch (type) { + case OSPF6_MESSAGE_TYPE_HELLO: + return "Hello"; + case OSPF6_MESSAGE_TYPE_DBDESC: + return "DbDesc"; + case OSPF6_MESSAGE_TYPE_LSREQ: + return "LSReq"; + case OSPF6_MESSAGE_TYPE_LSUPDATE: + return "LSUpdate"; + case OSPF6_MESSAGE_TYPE_LSACK: + return "LSAck"; + case OSPF6_MESSAGE_TYPE_UNKNOWN: + default: + return "unknown"; + } +} /* Minimum (besides the standard OSPF packet header) lengths for OSPF packets of particular types, offset is the "type" field. */ @@ -101,7 +117,7 @@ static void ospf6_header_print(struct ospf6_header *oh) void ospf6_hello_print(struct ospf6_header *oh, int action) { struct ospf6_hello *hello; - char options[16]; + char options[32]; char *p; ospf6_header_print(oh); @@ -136,7 +152,7 @@ void ospf6_hello_print(struct ospf6_header *oh, int action) void ospf6_dbdesc_print(struct ospf6_header *oh, int action) { struct ospf6_dbdesc *dbdesc; - char options[16]; + char options[32]; char *p; ospf6_header_print(oh); @@ -439,6 +455,20 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst, return; } + if (((OSPF6_OPT_ISSET_EXT(hello->options, OSPF6_OPT_AT) == + OSPF6_OPT_AT) && + (oi->at_data.flags == 0)) || + ((OSPF6_OPT_ISSET_EXT(hello->options, OSPF6_OPT_AT) != + OSPF6_OPT_AT) && + (oi->at_data.flags != 0))) { + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_warn( + "VRF %s: IF %s AT-bit mismatch in hello packet", + oi->interface->vrf->name, oi->interface->name); + oi->at_data.rx_drop++; + return; + } + /* Find neighbor, create if not exist */ on = ospf6_neighbor_lookup(oh->router_id, oi); if (on == NULL) { @@ -1006,6 +1036,20 @@ static void ospf6_dbdesc_recv(struct in6_addr *src, struct in6_addr *dst, dbdesc = (struct ospf6_dbdesc *)((caddr_t)oh + sizeof(struct ospf6_header)); + if (((OSPF6_OPT_ISSET_EXT(dbdesc->options, OSPF6_OPT_AT) == + OSPF6_OPT_AT) && + (oi->at_data.flags == 0)) || + ((OSPF6_OPT_ISSET_EXT(dbdesc->options, OSPF6_OPT_AT) != + OSPF6_OPT_AT) && + (oi->at_data.flags != 0))) { + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_warn( + "VRF %s: IF %s AT-bit mismatch in dbdesc packet", + oi->interface->vrf->name, oi->interface->name); + oi->at_data.rx_drop++; + return; + } + /* Interface MTU check */ if (!oi->mtu_ignore && ntohs(dbdesc->ifmtu) != oi->ifmtu) { zlog_warn("VRF %s: I/F %s MTU mismatch (my %d rcvd %d)", @@ -1412,14 +1456,15 @@ static unsigned ospf6_packet_examin(struct ospf6_header *oh, bytesonwire); return MSG_NG; } + /* Now it is safe to access header fields. */ if (bytesonwire != ntohs(oh->length)) { zlog_warn("%s: %s packet length error (%u real, %u declared)", - __func__, - lookup_msg(ospf6_message_type_str, oh->type, NULL), - bytesonwire, ntohs(oh->length)); + __func__, ospf6_message_type(oh->type), bytesonwire, + ntohs(oh->length)); return MSG_NG; } + /* version check */ if (oh->version != OSPFV3_VERSION) { zlog_warn("%s: invalid (%u) protocol version", __func__, @@ -1431,8 +1476,7 @@ static unsigned ospf6_packet_examin(struct ospf6_header *oh, && bytesonwire < OSPF6_HEADER_SIZE + ospf6_packet_minlen[oh->type]) { zlog_warn("%s: undersized (%u B) %s packet", __func__, - bytesonwire, - lookup_msg(ospf6_message_type_str, oh->type, NULL)); + bytesonwire, ospf6_message_type(oh->type)); return MSG_NG; } /* type-specific deeper validation */ @@ -1446,7 +1490,7 @@ static unsigned ospf6_packet_examin(struct ospf6_header *oh, % 4) return MSG_OK; zlog_warn("%s: alignment error in %s packet", __func__, - lookup_msg(ospf6_message_type_str, oh->type, NULL)); + ospf6_message_type(oh->type)); return MSG_NG; case OSPF6_MESSAGE_TYPE_DBDESC: /* RFC5340 A.3.3, packet header + OSPF6_DB_DESC_MIN_SIZE bytes @@ -1467,7 +1511,7 @@ static unsigned ospf6_packet_examin(struct ospf6_header *oh, % OSPF6_LSREQ_LSDESC_FIX_SIZE) return MSG_OK; zlog_warn("%s: alignment error in %s packet", __func__, - lookup_msg(ospf6_message_type_str, oh->type, NULL)); + ospf6_message_type(oh->type)); return MSG_NG; case OSPF6_MESSAGE_TYPE_LSUPDATE: /* RFC5340 A.3.5, packet header + OSPF6_LS_UPD_MIN_SIZE bytes @@ -1497,7 +1541,7 @@ static unsigned ospf6_packet_examin(struct ospf6_header *oh, } if (test != MSG_OK) zlog_warn("%s: anomaly in %s packet", __func__, - lookup_msg(ospf6_message_type_str, oh->type, NULL)); + ospf6_message_type(oh->type)); return test; } @@ -1727,6 +1771,9 @@ static int ospf6_read_helper(int sockfd, struct ospf6 *ospf6) struct iovec iovector[2]; struct ospf6_interface *oi; struct ospf6_header *oh; + enum ospf6_auth_err ret = OSPF6_AUTH_PROCESS_NORMAL; + uint32_t at_len = 0; + uint32_t lls_len = 0; /* initialize */ memset(&src, 0, sizeof(src)); @@ -1772,6 +1819,24 @@ static int ospf6_read_helper(int sockfd, struct ospf6 *ospf6) return OSPF6_READ_CONTINUE; oh = (struct ospf6_header *)recvbuf; + ret = ospf6_auth_validate_pkt(oi, (uint32_t *)&len, oh, &at_len, + &lls_len); + if (ret == OSPF6_AUTH_VALIDATE_SUCCESS) { + ret = ospf6_auth_check_digest(oh, oi, &src, lls_len); + if (ret == OSPF6_AUTH_VALIDATE_FAILURE) { + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_err( + "RECV[%s]: OSPF packet auth digest miss-match on %s", + oi->interface->name, + ospf6_message_type(oh->type)); + oi->at_data.rx_drop++; + return OSPF6_READ_CONTINUE; + } + } else if (ret == OSPF6_AUTH_VALIDATE_FAILURE) { + oi->at_data.rx_drop++; + return OSPF6_READ_CONTINUE; + } + if (ospf6_rxpacket_examin(oi, oh, len) != MSG_OK) return OSPF6_READ_CONTINUE; @@ -1782,8 +1847,7 @@ static int ospf6_read_helper(int sockfd, struct ospf6 *ospf6) /* Log */ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR)) { - zlog_debug("%s received on %s", - lookup_msg(ospf6_message_type_str, oh->type, NULL), + zlog_debug("%s received on %s", ospf6_message_type(oh->type), oi->interface->name); zlog_debug(" src: %pI6", &src); zlog_debug(" dst: %pI6", &dst); @@ -1807,6 +1871,10 @@ static int ospf6_read_helper(int sockfd, struct ospf6 *ospf6) default: assert(0); } + + if ((at_len != 0) && IS_OSPF6_DEBUG_AUTH_RX) + ospf6_auth_hdr_dump_recv(oh, (len + at_len + lls_len), + lls_len); } switch (oh->type) { @@ -1863,6 +1931,27 @@ int ospf6_receive(struct thread *thread) return 0; } +static void ospf6_fill_hdr_checksum(struct ospf6_interface *oi, + struct ospf6_packet *op) +{ + struct ipv6_ph ph = {}; + struct ospf6_header *oh; + void *offset = NULL; + + if (oi->at_data.flags != 0) + return; + + memcpy(&ph.src, oi->linklocal_addr, sizeof(struct in6_addr)); + memcpy(&ph.dst, &op->dst, sizeof(struct in6_addr)); + ph.ulpl = htonl(op->length); + ph.next_hdr = IPPROTO_OSPFIGP; + + /* Suppress static analysis warnings about accessing icmp6 oob */ + oh = (struct ospf6_header *)STREAM_DATA(op->s); + offset = oh; + oh->checksum = in_cksum_with_ph6(&ph, offset, op->length); +} + static void ospf6_make_header(uint8_t type, struct ospf6_interface *oi, struct stream *s) { @@ -1873,6 +1962,7 @@ static void ospf6_make_header(uint8_t type, struct ospf6_interface *oi, oh->version = (uint8_t)OSPFV3_VERSION; oh->type = type; oh->length = 0; + oh->router_id = oi->area->ospf6->router_id; oh->area_id = oi->area->area_id; oh->checksum = 0; @@ -1904,9 +1994,48 @@ static void ospf6_fill_lsupdate_header(struct stream *s, uint32_t lsa_num) lsu->lsa_number = htonl(lsa_num); } -static uint32_t ospf6_packet_max(struct ospf6_interface *oi) +static void ospf6_auth_trailer_copy_keychain_key(struct ospf6_interface *oi) +{ + char *keychain_name = NULL; + struct keychain *keychain = NULL; + struct key *key = NULL; + + keychain_name = oi->at_data.keychain; + keychain = keychain_lookup(keychain_name); + if (keychain) { + key = key_lookup_for_send(keychain); + if (key && key->string && + key->hash_algo != KEYCHAIN_ALGO_NULL) { + /* storing the values so that further + * lookup can be avoided. after + * processing the digest need to reset + * these values + */ + oi->at_data.hash_algo = key->hash_algo; + oi->at_data.auth_key = XSTRDUP( + MTYPE_OSPF6_AUTH_MANUAL_KEY, key->string); + oi->at_data.key_id = key->index; + SET_FLAG(oi->at_data.flags, + OSPF6_AUTH_TRAILER_KEYCHAIN_VALID); + } + } +} + +static uint16_t ospf6_packet_max(struct ospf6_interface *oi) { + uint16_t at_len = 0; + assert(oi->ifmtu > sizeof(struct ip6_hdr)); + + if (oi->at_data.flags != 0) { + if (CHECK_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_KEYCHAIN)) + ospf6_auth_trailer_copy_keychain_key(oi); + + at_len += OSPF6_AUTH_HDR_MIN_SIZE; + at_len += keychain_get_hash_len(oi->at_data.hash_algo); + return oi->ifmtu - (sizeof(struct ip6_hdr)) - at_len; + } + return oi->ifmtu - (sizeof(struct ip6_hdr)); } @@ -1915,11 +2044,15 @@ static uint16_t ospf6_make_hello(struct ospf6_interface *oi, struct stream *s) struct listnode *node, *nnode; struct ospf6_neighbor *on; uint16_t length = OSPF6_HELLO_MIN_SIZE; + uint8_t options1 = oi->area->options[1]; + + if (oi->at_data.flags != 0) + options1 |= OSPF6_OPT_AT; stream_putl(s, oi->interface->ifindex); stream_putc(s, oi->priority); stream_putc(s, oi->area->options[0]); - stream_putc(s, oi->area->options[1]); + stream_putc(s, options1); stream_putc(s, oi->area->options[2]); stream_putw(s, oi->hello_interval); stream_putw(s, oi->dead_interval); @@ -1959,6 +2092,7 @@ static int ospf6_write(struct thread *thread) int len; int64_t latency = 0; struct timeval timestamp; + uint16_t at_len = 0; if (ospf6->fd < 0) { zlog_warn("ospf6_write failed to send, fd %d", ospf6->fd); @@ -1983,17 +2117,32 @@ static int ospf6_write(struct thread *thread) oh = (struct ospf6_header *)STREAM_DATA(op->s); + if (oi->at_data.flags != 0) { + at_len = ospf6_auth_len_get(oi); + if (at_len) { + iovector[0].iov_len = + ntohs(oh->length) + at_len; + ospf6_auth_digest_send(oi->linklocal_addr, oi, + oh, at_len, + iovector[0].iov_len); + } else { + iovector[0].iov_len = ntohs(oh->length); + } + } else { + iovector[0].iov_len = ntohs(oh->length); + } + len = ospf6_sendmsg(oi->linklocal_addr, &op->dst, oi->interface->ifindex, iovector, ospf6->fd); - if (len != op->length) + + if (len != (op->length + (int)at_len)) flog_err(EC_LIB_DEVELOPMENT, "Could not send entire message"); if (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND_HDR)) { zlog_debug("%s send on %s", - lookup_msg(ospf6_message_type_str, oh->type, - NULL), + ospf6_message_type(oh->type), oi->interface->name); zlog_debug(" src: %pI6", oi->linklocal_addr); zlog_debug(" dst: %pI6", &op->dst); @@ -2052,6 +2201,15 @@ static int ospf6_write(struct thread *thread) assert(0); break; } + + if ((oi->at_data.flags != 0) && + (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND_HDR)) && + (IS_OSPF6_DEBUG_AUTH_TX)) + ospf6_auth_hdr_dump_send(oh, iovector[0].iov_len); + + /* initialize at_len to 0 for next packet */ + at_len = 0; + /* Now delete packet from queue. */ ospf6_packet_delete(oi); @@ -2117,6 +2275,8 @@ int ospf6_hello_send(struct thread *thread) op->dst = allspfrouters6; + ospf6_fill_hdr_checksum(oi, op); + /* Add packet to the top of the interface output queue, so that they * can't get delayed by things like long queues of LS Update packets */ @@ -2135,6 +2295,10 @@ static uint16_t ospf6_make_dbdesc(struct ospf6_neighbor *on, struct stream *s) { uint16_t length = OSPF6_DB_DESC_MIN_SIZE; struct ospf6_lsa *lsa, *lsanext; + uint8_t options1 = on->ospf6_if->area->options[1]; + + if (on->ospf6_if->at_data.flags != 0) + options1 |= OSPF6_OPT_AT; /* if this is initial one, initialize sequence number for DbDesc */ if (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT) @@ -2145,7 +2309,7 @@ static uint16_t ospf6_make_dbdesc(struct ospf6_neighbor *on, struct stream *s) /* reserved */ stream_putc(s, 0); /* reserved 1 */ stream_putc(s, on->ospf6_if->area->options[0]); - stream_putc(s, on->ospf6_if->area->options[1]); + stream_putc(s, options1); stream_putc(s, on->ospf6_if->area->options[2]); stream_putw(s, on->ospf6_if->ifmtu); stream_putc(s, 0); /* reserved 2 */ @@ -2212,6 +2376,8 @@ int ospf6_dbdesc_send(struct thread *thread) else op->dst = on->linklocal_addr; + ospf6_fill_hdr_checksum(on->ospf6_if, op); + ospf6_packet_add(on->ospf6_if, op); OSPF6_MESSAGE_WRITE_ON(on->ospf6_if); @@ -2319,6 +2485,7 @@ static uint16_t ospf6_make_lsack_neighbor(struct ospf6_neighbor *on, (*op)->length = length + OSPF6_HEADER_SIZE; (*op)->dst = on->linklocal_addr; + ospf6_fill_hdr_checksum(on->ospf6_if, *op); ospf6_packet_add(on->ospf6_if, *op); OSPF6_MESSAGE_WRITE_ON(on->ospf6_if); /* new packet */ @@ -2388,6 +2555,7 @@ int ospf6_lsreq_send(struct thread *thread) else op->dst = on->linklocal_addr; + ospf6_fill_hdr_checksum(on->ospf6_if, op); ospf6_packet_add(on->ospf6_if, op); OSPF6_MESSAGE_WRITE_ON(on->ospf6_if); @@ -2425,6 +2593,7 @@ static void ospf6_send_lsupdate(struct ospf6_neighbor *on, op->dst = alldrouters6; } if (oi) { + ospf6_fill_hdr_checksum(oi, op); ospf6_packet_add(oi, op); /* If ospf instance is being deleted, send the packet * immediately @@ -2452,9 +2621,8 @@ static uint16_t ospf6_make_lsupdate_list(struct ospf6_neighbor *on, stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE); for (ALL_LSDB(on->lsupdate_list, lsa, lsanext)) { - if ((length + (unsigned int)OSPF6_LSA_SIZE(lsa->header) - + OSPF6_HEADER_SIZE) - > ospf6_packet_max(on->ospf6_if)) { + if ((length + OSPF6_LSA_SIZE(lsa->header) + OSPF6_HEADER_SIZE) > + ospf6_packet_max(on->ospf6_if)) { ospf6_fill_header(on->ospf6_if, (*op)->s, length + OSPF6_HEADER_SIZE); (*op)->length = length + OSPF6_HEADER_SIZE; @@ -2490,9 +2658,8 @@ static uint16_t ospf6_make_ls_retrans_list(struct ospf6_neighbor *on, stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE); for (ALL_LSDB(on->retrans_list, lsa, lsanext)) { - if ((length + (unsigned int)OSPF6_LSA_SIZE(lsa->header) - + OSPF6_HEADER_SIZE) - > ospf6_packet_max(on->ospf6_if)) { + if ((length + OSPF6_LSA_SIZE(lsa->header) + OSPF6_HEADER_SIZE) > + ospf6_packet_max(on->ospf6_if)) { ospf6_fill_header(on->ospf6_if, (*op)->s, length + OSPF6_HEADER_SIZE); (*op)->length = length + OSPF6_HEADER_SIZE; @@ -2502,6 +2669,7 @@ static uint16_t ospf6_make_ls_retrans_list(struct ospf6_neighbor *on, else (*op)->dst = on->linklocal_addr; + ospf6_fill_hdr_checksum(on->ospf6_if, *op); ospf6_packet_add(on->ospf6_if, *op); OSPF6_MESSAGE_WRITE_ON(on->ospf6_if); @@ -2573,6 +2741,7 @@ int ospf6_lsupdate_send_neighbor(struct thread *thread) op->dst = allspfrouters6; else op->dst = on->linklocal_addr; + ospf6_fill_hdr_checksum(on->ospf6_if, op); ospf6_packet_add(on->ospf6_if, op); OSPF6_MESSAGE_WRITE_ON(on->ospf6_if); } else @@ -2629,9 +2798,8 @@ static uint16_t ospf6_make_lsupdate_interface(struct ospf6_interface *oi, stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE); for (ALL_LSDB(oi->lsupdate_list, lsa, lsanext)) { - if (length + (unsigned int)OSPF6_LSA_SIZE(lsa->header) - + OSPF6_HEADER_SIZE - > ospf6_packet_max(oi)) { + if (length + OSPF6_LSA_SIZE(lsa->header) + OSPF6_HEADER_SIZE > + ospf6_packet_max(oi)) { ospf6_fill_header(oi, (*op)->s, length + OSPF6_HEADER_SIZE); (*op)->length = length + OSPF6_HEADER_SIZE; @@ -2739,6 +2907,7 @@ int ospf6_lsack_send_neighbor(struct thread *thread) /* Set packet length, dst and queue to FIFO. */ op->length = length; op->dst = on->linklocal_addr; + ospf6_fill_hdr_checksum(on->ospf6_if, op); ospf6_packet_add(on->ospf6_if, op); OSPF6_MESSAGE_WRITE_ON(on->ospf6_if); @@ -2823,6 +2992,7 @@ int ospf6_lsack_send_interface(struct thread *thread) else op->dst = alldrouters6; + ospf6_fill_hdr_checksum(oi, op); ospf6_packet_add(oi, op); OSPF6_MESSAGE_WRITE_ON(oi); diff --git a/ospf6d/ospf6_message.h b/ospf6d/ospf6_message.h index 0cd10ef825..437dd5685b 100644 --- a/ospf6d/ospf6_message.h +++ b/ospf6d/ospf6_message.h @@ -25,6 +25,7 @@ /* Debug option */ extern unsigned char conf_debug_ospf6_message[]; + #define OSPF6_ACTION_SEND 0x01 #define OSPF6_ACTION_RECV 0x02 #define OSPF6_DEBUG_MESSAGE_SEND 0x01 @@ -62,6 +63,7 @@ extern unsigned char conf_debug_ospf6_message[]; #define OSPF6_MESSAGE_TYPE_LSUPDATE 0x4 /* Database update */ #define OSPF6_MESSAGE_TYPE_LSACK 0x5 /* Flooding acknowledgment */ #define OSPF6_MESSAGE_TYPE_ALL 0x6 /* For debug option */ +#define OSPF6_MESSAGE_TYPE_MAX 0x6 /* same as OSPF6_MESSAGE_TYPE_ALL */ struct ospf6_packet { struct ospf6_packet *next; @@ -146,8 +148,16 @@ struct ospf6_lsupdate { /* Followed by LSAs */ }; +/* LLS is not supported, but used to derive + * offset of Auth_trailer + */ +struct ospf6_lls_hdr { + uint16_t checksum; + uint16_t length; +}; + /* Link State Acknowledgement */ -#define OSPF6_LS_ACK_MIN_SIZE 0U +#define OSPF6_LS_ACK_MIN_SIZE 0U /* It is just a sequence of LSA Headers */ /* Function definition */ @@ -176,5 +186,5 @@ extern int ospf6_lsack_send_neighbor(struct thread *thread); extern int config_write_ospf6_debug_message(struct vty *); extern void install_element_ospf6_debug_message(void); - +extern const char *ospf6_message_type(int type); #endif /* OSPF6_MESSAGE_H */ diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c index afa504d13c..5d14bfc981 100644 --- a/ospf6d/ospf6_neighbor.c +++ b/ospf6d/ospf6_neighbor.c @@ -112,6 +112,7 @@ struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id, { struct ospf6_neighbor *on; char buf[16]; + int type; on = XCALLOC(MTYPE_OSPF6_NEIGHBOR, sizeof(struct ospf6_neighbor)); inet_ntop(AF_INET, &router_id, buf, sizeof(buf)); @@ -131,6 +132,13 @@ struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id, on->lsupdate_list = ospf6_lsdb_create(on); on->lsack_list = ospf6_lsdb_create(on); + for (type = 0; type < OSPF6_MESSAGE_TYPE_MAX; type++) { + on->seqnum_l[type] = 0; + on->seqnum_h[type] = 0; + } + + on->auth_present = false; + listnode_add_sort(oi->neighbor_list, on); ospf6_bfd_info_nbr_create(oi, on); @@ -935,8 +943,44 @@ static void ospf6_neighbor_show_detail(struct vty *vty, bfd_sess_show(vty, json_neighbor, on->bfd_session); - json_object_object_add(json, on->name, json_neighbor); + if (on->auth_present == true) { + json_object_string_add(json_neighbor, "authStatus", + "enabled"); + json_object_int_add( + json_neighbor, "recvdHelloHigherSeqNo", + on->seqnum_h[OSPF6_MESSAGE_TYPE_HELLO]); + json_object_int_add( + json_neighbor, "recvdHelloLowerSeqNo", + on->seqnum_l[OSPF6_MESSAGE_TYPE_HELLO]); + json_object_int_add( + json_neighbor, "recvdDBDescHigherSeqNo", + on->seqnum_h[OSPF6_MESSAGE_TYPE_DBDESC]); + json_object_int_add( + json_neighbor, "recvdDBDescLowerSeqNo", + on->seqnum_l[OSPF6_MESSAGE_TYPE_DBDESC]); + json_object_int_add( + json_neighbor, "recvdLSReqHigherSeqNo", + on->seqnum_h[OSPF6_MESSAGE_TYPE_LSREQ]); + json_object_int_add( + json_neighbor, "recvdLSReqLowerSeqNo", + on->seqnum_l[OSPF6_MESSAGE_TYPE_LSREQ]); + json_object_int_add( + json_neighbor, "recvdLSUpdHigherSeqNo", + on->seqnum_h[OSPF6_MESSAGE_TYPE_LSUPDATE]); + json_object_int_add( + json_neighbor, "recvdLSUpdLowerSeqNo", + on->seqnum_l[OSPF6_MESSAGE_TYPE_LSUPDATE]); + json_object_int_add( + json_neighbor, "recvdLSAckHigherSeqNo", + on->seqnum_h[OSPF6_MESSAGE_TYPE_LSACK]); + json_object_int_add( + json_neighbor, "recvdLSAckLowerSeqNo", + on->seqnum_l[OSPF6_MESSAGE_TYPE_LSACK]); + } else + json_object_string_add(json_neighbor, "authStatus", + "disabled"); + json_object_object_add(json, on->name, json_neighbor); } else { vty_out(vty, " Neighbor %s\n", on->name); @@ -1022,6 +1066,27 @@ static void ospf6_neighbor_show_detail(struct vty *vty, vty_out(vty, " %s\n", lsa->name); bfd_sess_show(vty, NULL, on->bfd_session); + + if (on->auth_present == true) { + vty_out(vty, " Authentication header present\n"); + vty_out(vty, + "\t\t\t hello DBDesc LSReq LSUpd LSAck\n"); + vty_out(vty, + " Higher sequence no 0x%-10X 0x%-10X 0x%-10X 0x%-10X 0x%-10X\n", + on->seqnum_h[OSPF6_MESSAGE_TYPE_HELLO], + on->seqnum_h[OSPF6_MESSAGE_TYPE_DBDESC], + on->seqnum_h[OSPF6_MESSAGE_TYPE_LSREQ], + on->seqnum_h[OSPF6_MESSAGE_TYPE_LSUPDATE], + on->seqnum_h[OSPF6_MESSAGE_TYPE_LSACK]); + vty_out(vty, + " Lower sequence no 0x%-10X 0x%-10X 0x%-10X 0x%-10X 0x%-10X\n", + on->seqnum_l[OSPF6_MESSAGE_TYPE_HELLO], + on->seqnum_l[OSPF6_MESSAGE_TYPE_DBDESC], + on->seqnum_l[OSPF6_MESSAGE_TYPE_LSREQ], + on->seqnum_l[OSPF6_MESSAGE_TYPE_LSUPDATE], + on->seqnum_l[OSPF6_MESSAGE_TYPE_LSACK]); + } else + vty_out(vty, " Authentication header not present\n"); } } diff --git a/ospf6d/ospf6_neighbor.h b/ospf6d/ospf6_neighbor.h index de59a1ccf5..2dd640099c 100644 --- a/ospf6d/ospf6_neighbor.h +++ b/ospf6d/ospf6_neighbor.h @@ -144,6 +144,14 @@ struct ospf6_neighbor { /* ospf6 graceful restart HELPER info */ struct ospf6_helper_info gr_helper_info; + + /* seqnum_h/l is used to compare sequence + * number in received packet Auth header + */ + uint32_t seqnum_h[OSPF6_MESSAGE_TYPE_MAX]; + uint32_t seqnum_l[OSPF6_MESSAGE_TYPE_MAX]; + bool auth_present; + bool lls_present; }; /* Neighbor state */ diff --git a/ospf6d/ospf6_network.c b/ospf6d/ospf6_network.c index 5961cfe66a..7501f49fe0 100644 --- a/ospf6d/ospf6_network.c +++ b/ospf6d/ospf6_network.c @@ -33,6 +33,7 @@ #include "ospf6_top.h" #include "ospf6_network.h" #include "ospf6d.h" +#include "ospf6_message.h" struct in6_addr allspfrouters6; struct in6_addr alldrouters6; @@ -60,20 +61,6 @@ static void ospf6_set_transport_class(int ospf6_sock) #endif } -static void ospf6_set_checksum(int ospf6_sock) -{ - int offset = 12; -#ifndef DISABLE_IPV6_CHECKSUM - if (setsockopt(ospf6_sock, IPPROTO_IPV6, IPV6_CHECKSUM, &offset, - sizeof(offset)) - < 0) - zlog_warn("Network: set IPV6_CHECKSUM failed: %s", - safe_strerror(errno)); -#else - zlog_warn("Network: Don't set IPV6_CHECKSUM"); -#endif /* DISABLE_IPV6_CHECKSUM */ -} - void ospf6_serv_close(int *ospf6_sock) { if (*ospf6_sock != -1) { @@ -113,7 +100,6 @@ int ospf6_serv_sock(struct ospf6 *ospf6) ospf6_reset_mcastloop(ospf6_sock); ospf6_set_pktinfo(ospf6_sock); ospf6_set_transport_class(ospf6_sock); - ospf6_set_checksum(ospf6_sock); ospf6->fd = ospf6_sock; /* setup global in6_addr, allspf6 and alldr6 for later use */ diff --git a/ospf6d/ospf6_proto.c b/ospf6d/ospf6_proto.c index e60d2c7e0e..4d0c4ee59e 100644 --- a/ospf6d/ospf6_proto.c +++ b/ospf6d/ospf6_proto.c @@ -82,12 +82,16 @@ void ospf6_capability_printbuf(char capability, char *buf, int size) void ospf6_options_printbuf(uint8_t *options, char *buf, int size) { - const char *dc, *r, *n, *mc, *e, *v6; + const char *dc, *r, *n, *mc, *e, *v6, *af, *at, *l; dc = (OSPF6_OPT_ISSET(options, OSPF6_OPT_DC) ? "DC" : "--"); r = (OSPF6_OPT_ISSET(options, OSPF6_OPT_R) ? "R" : "-"); n = (OSPF6_OPT_ISSET(options, OSPF6_OPT_N) ? "N" : "-"); mc = (OSPF6_OPT_ISSET(options, OSPF6_OPT_MC) ? "MC" : "--"); e = (OSPF6_OPT_ISSET(options, OSPF6_OPT_E) ? "E" : "-"); v6 = (OSPF6_OPT_ISSET(options, OSPF6_OPT_V6) ? "V6" : "--"); - snprintf(buf, size, "%s|%s|%s|%s|%s|%s", dc, r, n, mc, e, v6); + af = (OSPF6_OPT_ISSET_EXT(options, OSPF6_OPT_AF) ? "AF" : "--"); + at = (OSPF6_OPT_ISSET_EXT(options, OSPF6_OPT_AT) ? "AT" : "--"); + l = (OSPF6_OPT_ISSET_EXT(options, OSPF6_OPT_L) ? "L" : "-"); + snprintf(buf, size, "%s|%s|%s|-|-|%s|%s|%s|%s|%s|%s", at, l, af, dc, r, + n, mc, e, v6); } diff --git a/ospf6d/ospf6_proto.h b/ospf6d/ospf6_proto.h index b98dc38b72..ea476b3a8d 100644 --- a/ospf6d/ospf6_proto.h +++ b/ospf6d/ospf6_proto.h @@ -40,13 +40,20 @@ /* OSPF options */ /* present in HELLO, DD, LSA */ -#define OSPF6_OPT_SET(x,opt) ((x)[2] |= (opt)) -#define OSPF6_OPT_ISSET(x,opt) ((x)[2] & (opt)) -#define OSPF6_OPT_CLEAR(x,opt) ((x)[2] &= ~(opt)) +#define OSPF6_OPT_SET(x, opt) ((x)[2] |= (opt)) +#define OSPF6_OPT_ISSET(x, opt) ((x)[2] & (opt)) +#define OSPF6_OPT_CLEAR(x, opt) ((x)[2] &= ~(opt)) +#define OSPF6_OPT_SET_EXT(x, opt) ((x)[1] |= (opt)) +#define OSPF6_OPT_ISSET_EXT(x, opt) ((x)[1] & (opt)) +#define OSPF6_OPT_CLEAR_EXT(x, opt) ((x)[1] &= ~(opt)) #define OSPF6_OPT_CLEAR_ALL(x) ((x)[0] = (x)[1] = (x)[2] = 0) +#define OSPF6_OPT_AT (1 << 2) /* Authentication trailer Capability */ +#define OSPF6_OPT_L (1 << 1) /* Link local signalling Capability */ +#define OSPF6_OPT_AF (1 << 0) /* Address family Capability */ +/* 2 bits reserved for OSPFv2 migrated options */ #define OSPF6_OPT_DC (1 << 5) /* Demand Circuit handling Capability */ -#define OSPF6_OPT_R (1 << 4) /* Forwarding Capability (Any Protocol) */ +#define OSPF6_OPT_R (1 << 4) /* Forwarding Capability (Any Protocol) */ #define OSPF6_OPT_N (1 << 3) /* Handling Type-7 LSA Capability */ #define OSPF6_OPT_MC (1 << 2) /* Multicasting Capability */ #define OSPF6_OPT_E (1 << 1) /* AS External Capability */ diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index f5d60d80fa..3c74ca55c1 100644 --- a/ospf6d/ospf6_route.c +++ b/ospf6d/ospf6_route.c @@ -1168,7 +1168,7 @@ void ospf6_route_show_detail(struct vty *vty, struct ospf6_route *route, json_object *json_routes, bool use_json) { char destination[PREFIX2STR_BUFFER], nexthop[64]; - char area_id[16], id[16], adv_router[16], capa[16], options[16]; + char area_id[16], id[16], adv_router[16], capa[16], options[32]; char pfx_options[16]; struct timeval now, res; char duration[64]; @@ -1653,7 +1653,7 @@ static void ospf6_linkstate_show_header(struct vty *vty) static void ospf6_linkstate_show(struct vty *vty, struct ospf6_route *route) { uint32_t router, id; - char routername[16], idname[16], rbits[16], options[16]; + char routername[16], idname[16], rbits[16], options[32]; router = ospf6_linkstate_prefix_adv_router(&route->prefix); inet_ntop(AF_INET, &router, routername, sizeof(routername)); @@ -1779,7 +1779,7 @@ void ospf6_brouter_show_header(struct vty *vty) void ospf6_brouter_show(struct vty *vty, struct ospf6_route *route) { uint32_t adv_router; - char adv[16], rbits[16], options[16], area[16]; + char adv[16], rbits[16], options[32], area[16]; adv_router = ospf6_linkstate_prefix_adv_router(&route->prefix); inet_ntop(AF_INET, &adv_router, adv, sizeof(adv)); diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 57a55a6ef4..13f16efa66 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -54,6 +54,7 @@ #include "ospf6_gr.h" #include "lib/json.h" #include "ospf6_nssa.h" +#include "ospf6_auth_trailer.h" DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_TOP, "OSPF6 top"); @@ -445,6 +446,17 @@ static struct ospf6 *ospf6_create(const char *name) /* Make ospf protocol socket. */ ospf6_serv_sock(o); + /* If sequence number is stored in persistent storage, read it. + */ + if (ospf6_auth_nvm_file_exist() == OSPF6_AUTH_FILE_EXIST) { + ospf6_auth_seqno_nvm_read(o); + o->seqnum_h = o->seqnum_h + 1; + ospf6_auth_seqno_nvm_update(o); + } else { + o->seqnum_l = o->seqnum_h = 0; + ospf6_auth_seqno_nvm_update(o); + } + return o; } @@ -1386,6 +1398,10 @@ static void ospf6_show(struct vty *vty, struct ospf6 *o, json_object *json, json_object_int_add(json, "numberOfAreaInRouter", listcount(o->area_list)); + json_object_int_add(json, "AuthTrailerHigherSeqNo", + o->seqnum_h); + json_object_int_add(json, "AuthTrailerLowerSeqNo", o->seqnum_l); + if (CHECK_FLAG(o->config_flags, OSPF6_LOG_ADJACENCY_CHANGES)) { if (CHECK_FLAG(o->config_flags, OSPF6_LOG_ADJACENCY_DETAIL)) @@ -1466,6 +1482,10 @@ static void ospf6_show(struct vty *vty, struct ospf6 *o, json_object *json, vty_out(vty, " Number of areas in this router is %u\n", listcount(o->area_list)); + vty_out(vty, " Authentication Sequence number info\n"); + vty_out(vty, " Higher sequence no %u, Lower sequence no %u\n", + o->seqnum_h, o->seqnum_l); + if (CHECK_FLAG(o->config_flags, OSPF6_LOG_ADJACENCY_CHANGES)) { if (CHECK_FLAG(o->config_flags, OSPF6_LOG_ADJACENCY_DETAIL)) @@ -2117,7 +2137,7 @@ DEFPY (show_ipv6_ospf6_external_aggregator, VRF_CMD_HELP_STR "All VRFs\n" "Show external summary addresses\n" - "detailed informtion\n" + "detailed information\n" JSON_STR) { bool uj = use_json(argc, argv); diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h index b9f7235b46..f06a3254ac 100644 --- a/ospf6d/ospf6_top.h +++ b/ospf6d/ospf6_top.h @@ -228,6 +228,8 @@ struct ospf6 { /* Action for aggregation of external LSAs */ int aggr_action; + uint32_t seqnum_l; /* lower order Sequence Number */ + uint32_t seqnum_h; /* higher order Sequence Number */ #define OSPF6_EXTL_AGGR_DEFAULT_DELAY 5 /* For ASBR summary delay timer */ uint16_t aggr_delay_interval; diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index 82d280811b..e279d0411b 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -354,7 +354,7 @@ DEFUN(show_zebra, vty_json(vty, json); } else { - vty_out(vty, "Zebra Infomation\n"); + vty_out(vty, "Zebra Information\n"); vty_out(vty, " fail: %d\n", zclient->fail); vty_out(vty, " redistribute default: %d\n", vrf_bitmap_check(zclient->default_information[AFI_IP6], diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c index cc5a0f7870..a16f4f73eb 100644 --- a/ospf6d/ospf6d.c +++ b/ospf6d/ospf6d.c @@ -48,6 +48,7 @@ #include "ospf6_gr.h" #include "lib/json.h" #include "ospf6_nssa.h" +#include "ospf6_auth_trailer.h" DEFINE_MGROUP(OSPF6D, "ospf6d"); @@ -98,6 +99,7 @@ static int config_write_ospf6_debug(struct vty *vty) config_write_ospf6_debug_flood(vty); config_write_ospf6_debug_nssa(vty); config_write_ospf6_debug_gr_helper(vty); + config_write_ospf6_debug_auth(vty); return 0; } @@ -1458,4 +1460,7 @@ void ospf6_init(struct thread_master *master) VIEW_NODE, &show_ipv6_ospf6_database_type_self_originated_linkstate_id_cmd); install_element(VIEW_NODE, &show_ipv6_ospf6_database_aggr_router_cmd); + install_element_ospf6_debug_auth(); + ospf6_interface_auth_trailer_cmd_init(); + install_element_ospf6_clear_intf_auth(); } diff --git a/ospf6d/subdir.am b/ospf6d/subdir.am index 34aabc205b..cf863ff523 100644 --- a/ospf6d/subdir.am +++ b/ospf6d/subdir.am @@ -24,6 +24,7 @@ vtysh_scan += \ ospf6d/ospf6_top.c \ ospf6d/ospf6_zebra.c \ ospf6d/ospf6d.c \ + ospf6d/ospf6_auth_trailer.c \ # end vtysh_daemons += ospf6d if SNMP @@ -56,6 +57,7 @@ ospf6d_libospf6_a_SOURCES = \ ospf6d/ospf6_top.c \ ospf6d/ospf6_zebra.c \ ospf6d/ospf6d.c \ + ospf6d/ospf6_auth_trailer.c \ # end noinst_HEADERS += \ @@ -80,6 +82,7 @@ noinst_HEADERS += \ ospf6d/ospf6_top.h \ ospf6d/ospf6_zebra.h \ ospf6d/ospf6d.h \ + ospf6d/ospf6_auth_trailer.h \ # end ospf6d_ospf6d_LDADD = ospf6d/libospf6.a lib/libfrr.la $(LIBCAP) diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c index f44e1dde82..db78e6d2df 100644 --- a/ospfd/ospf_asbr.c +++ b/ospfd/ospf_asbr.c @@ -207,7 +207,7 @@ struct ospf_lsa *ospf_external_info_find_lsa(struct ospf *ospf, struct as_external_lsa *al; struct in_addr mask, id; - /* Fisrt search the lsdb with address specifc LSID + /* First search the lsdb with address specific LSID * where all the host bits are set, if there a matched * LSA, return. * Ex: For route 10.0.0.0/16, LSID is 10.0.255.255 @@ -630,7 +630,7 @@ struct ospf_lsa *ospf_originate_summary_lsa(struct ospf *ospf, ospf_link_ei_to_aggr(aggr, ei); lsa = ospf_external_info_find_lsa(ospf, &aggr->p); - /* Dont originate external LSA, + /* Don't originate external LSA, * If it is configured not to advertise. */ if (CHECK_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE)) { @@ -787,12 +787,12 @@ static void ospf_handle_aggregated_exnl_rt(struct ospf *ospf, /* Handling the case where the external route prefix * and aggregate prefix is same - * If same dont flush the originated external LSA. + * If same don't flush the originated external LSA. */ if (prefix_same((struct prefix *)&aggr->p, (struct prefix *)&ei->p)) { if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR)) zlog_debug( - "%s: External Route prefix same as Aggregator(%pI4/%d), so dont flush.", + "%s: External Route prefix same as Aggregator(%pI4/%d), so don't flush.", __func__, &ei->p.prefix, ei->p.prefixlen); return; } diff --git a/ospfd/ospf_gr_helper.c b/ospfd/ospf_gr_helper.c index ae002fdc97..5eca591754 100644 --- a/ospfd/ospf_gr_helper.c +++ b/ospfd/ospf_gr_helper.c @@ -847,8 +847,8 @@ void ospf_gr_helper_support_set(struct ospf *ospf, bool support) lookup.advRtrAddr.s_addr = nbr->router_id.s_addr; /* check if helper support enabled for the - * corresponding routerid.If enabled, dont - * dont exit from helper role. + * corresponding routerid.If enabled, don't + * exit from helper role. */ if (hash_lookup(ospf->enable_rtr_list, &lookup)) continue; diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 32d87b9a91..0b7c3c6831 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -10398,7 +10398,7 @@ DEFPY (show_ip_ospf_gr_helper, "All VRFs\n" "OSPF Graceful Restart\n" "Helper details in the router\n" - "Detailed informtion\n" + "Detailed information\n" JSON_STR) { char *vrf_name = NULL; @@ -11500,7 +11500,7 @@ DEFUN (show_ip_ospf_external_aggregator, VRF_CMD_HELP_STR "All VRFs\n" "Show external summary addresses\n" - "Detailed informtion\n" + "Detailed information\n" JSON_STR) { char *vrf_name = NULL; diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index 7834b7d934..66b7425a81 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -1380,7 +1380,7 @@ static int ospf_zebra_read_route(ZAPI_CALLBACK_ARGS) /* Handling the case where the * external route prefix * and aggegate prefix is same - * If same dont flush the + * If same don't flush the * originated * external LSA. */ diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index e5f3eec603..b1bba9eb4e 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -1089,7 +1089,7 @@ struct ospf_interface *add_ospf_interface(struct connected *co, ospf_ldp_sync_if_init(oi); /* - * if router_id is not configured, dont bring up + * if router_id is not configured, don't bring up * interfaces. * ospf_router_id_update() will call ospf_if_update * whenever r-id is configured instead. diff --git a/pathd/path_errors.c b/pathd/path_errors.c index 112a3d5ee9..68372c29b6 100644 --- a/pathd/path_errors.c +++ b/pathd/path_errors.c @@ -81,7 +81,7 @@ static struct log_ref ferr_path_warn[] = { { .code = EC_PATH_PCEP_UNSUPPORTED_PCEP_FEATURE, .title = "Unsupported PCEP feature", - .description = "Receved an unsupported PCEP message", + .description = "Received an unsupported PCEP message", .suggestion = "The PCC and PCE are probably not compatible. Open an Issue with all relevant log files" }, { diff --git a/pathd/path_pcep_config.c b/pathd/path_pcep_config.c index 4c16b83948..99b1c349a9 100644 --- a/pathd/path_pcep_config.c +++ b/pathd/path_pcep_config.c @@ -301,7 +301,7 @@ int path_pcep_config_initiate_path(struct path *path) return ERROR_19_9; } zlog_warn( - "(%s)PCE tried to REMOVE found canidate!, let's remove", + "(%s)PCE tried to REMOVE found candidate!, let's remove", __func__); candidate->policy->srp_id = path->srp_id; SET_FLAG(candidate->policy->flags, F_POLICY_DELETED); diff --git a/pathd/pathd.c b/pathd/pathd.c index 7f6d34f752..f56da37b51 100644 --- a/pathd/pathd.c +++ b/pathd/pathd.c @@ -1345,7 +1345,7 @@ int32_t srte_ted_do_query_type_c(struct srte_segment_entry *entry, zlog_warn(" %s: PATHD-TED: SL: ERROR query C : ted-sid (%d)", __func__, ted_sid); } else { - zlog_debug("%s: PATHD-TED: SL: Sucess query C : ted-sid (%d)", + zlog_debug("%s: PATHD-TED: SL: Success query C : ted-sid (%d)", __func__, ted_sid); } if (CHECK_SID(entry->segment_list->protocol_origin, ted_sid, @@ -1375,7 +1375,7 @@ int32_t srte_ted_do_query_type_e(struct srte_segment_entry *entry, zlog_warn(" %s: PATHD-TED: SL: ERROR query E : ted-sid (%d)", __func__, ted_sid); } else { - zlog_debug("%s: PATHD-TED: SL: Sucess query E : ted-sid (%d)", + zlog_debug("%s: PATHD-TED: SL: Success query E : ted-sid (%d)", __func__, ted_sid); } if (CHECK_SID(entry->segment_list->protocol_origin, ted_sid, @@ -1404,7 +1404,7 @@ int32_t srte_ted_do_query_type_f(struct srte_segment_entry *entry, zlog_warn("%s:SL: ERROR query F : ted-sid (%d)", __func__, ted_sid); } else { - zlog_debug("%s:SL: Sucess query F : ted-sid (%d)", __func__, + zlog_debug("%s:SL: Success query F : ted-sid (%d)", __func__, ted_sid); } if (CHECK_SID(entry->segment_list->protocol_origin, ted_sid, diff --git a/pceplib/pcep_timers.c b/pceplib/pcep_timers.c index bbf9b77983..b0f3e70b50 100644 --- a/pceplib/pcep_timers.c +++ b/pceplib/pcep_timers.c @@ -413,7 +413,7 @@ bool reset_timer(int timer_id) /* Keeping this log for now, since in older versions of FRR the * timer cancellation was blocking. This allows us to see how * long the it takes.*/ - pcep_log(LOG_DEBUG, "%s: Reseting timer [%d] with callback", + pcep_log(LOG_DEBUG, "%s: Resetting timer [%d] with callback", __func__, timer_to_reset->timer_id); timers_context_->timer_cancel_func( &timer_to_reset->external_timer); diff --git a/pimd/pim_assert.c b/pimd/pim_assert.c index 3c38ebd76b..7d05403c36 100644 --- a/pimd/pim_assert.c +++ b/pimd/pim_assert.c @@ -61,18 +61,11 @@ void pim_ifassert_winner_set(struct pim_ifchannel *ch, ch->interface->name); } - if (winner_changed) { - char was_str[INET_ADDRSTRLEN]; - char winner_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<was?>", ch->ifassert_winner, was_str, - sizeof(was_str)); - pim_inet4_dump("<winner?>", winner, winner_str, - sizeof(winner_str)); + if (winner_changed) zlog_debug( - "%s: (S,G)=%s assert winner changed from %s to %s on interface %s", - __func__, ch->sg_str, was_str, winner_str, - ch->interface->name); - } + "%s: (S,G)=%s assert winner changed from %pPAs to %pPAs on interface %s", + __func__, ch->sg_str, &ch->ifassert_winner, + &winner, ch->interface->name); } /* PIM_DEBUG_PIM_EVENTS */ ch->ifassert_state = new_state; @@ -87,14 +80,10 @@ void pim_ifassert_winner_set(struct pim_ifchannel *ch, } } -static void on_trace(const char *label, struct interface *ifp, - struct in_addr src) +static void on_trace(const char *label, struct interface *ifp, pim_addr src) { - if (PIM_DEBUG_PIM_TRACE) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src, src_str, sizeof(src_str)); - zlog_debug("%s: from %s on %s", label, src_str, ifp->name); - } + if (PIM_DEBUG_PIM_TRACE) + zlog_debug("%s: from %pPAs on %s", label, &src, ifp->name); } static int preferred_assert(const struct pim_ifchannel *ch, @@ -136,8 +125,8 @@ static void if_could_assert_do_a1(const char *caller, struct pim_ifchannel *ch) } } -static int dispatch_assert(struct interface *ifp, struct in_addr source_addr, - struct in_addr group_addr, +static int dispatch_assert(struct interface *ifp, pim_addr source_addr, + pim_addr group_addr, struct pim_assert_metric recv_metric) { struct pim_ifchannel *ch; @@ -213,10 +202,11 @@ static int dispatch_assert(struct interface *ifp, struct in_addr source_addr, } int pim_assert_recv(struct interface *ifp, struct pim_neighbor *neigh, - struct in_addr src_addr, uint8_t *buf, int buf_size) + pim_addr src_addr, uint8_t *buf, int buf_size) { pim_sgaddr sg; - struct prefix msg_source_addr; + pim_addr msg_source_addr; + bool wrong_af = false; struct pim_assert_metric msg_metric; int offset; uint8_t *curr; @@ -234,10 +224,9 @@ int pim_assert_recv(struct interface *ifp, struct pim_neighbor *neigh, memset(&sg, 0, sizeof(sg)); offset = pim_parse_addr_group(&sg, curr, curr_size); if (offset < 1) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: pim_parse_addr_group() failure: from %s on %s", - __func__, src_str, ifp->name); + zlog_warn( + "%s: pim_parse_addr_group() failure: from %pPAs on %s", + __func__, &src_addr, ifp->name); return -1; } curr += offset; @@ -246,23 +235,21 @@ int pim_assert_recv(struct interface *ifp, struct pim_neighbor *neigh, /* Parse assert source addr */ - offset = pim_parse_addr_ucast(&msg_source_addr, curr, curr_size); - if (offset < 1) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s", - __func__, src_str, ifp->name); + offset = pim_parse_addr_ucast(&msg_source_addr, curr, curr_size, + &wrong_af); + if (offset < 1 || wrong_af) { + zlog_warn( + "%s: pim_parse_addr_ucast() failure: from %pPAs on %s", + __func__, &src_addr, ifp->name); return -2; } curr += offset; curr_size -= offset; if (curr_size < 8) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); zlog_warn( - "%s: preference/metric size is less than 8 bytes: size=%d from %s on interface %s", - __func__, curr_size, src_str, ifp->name); + "%s: preference/metric size is less than 8 bytes: size=%d from %pPAs on interface %s", + __func__, curr_size, &src_addr, ifp->name); return -3; } @@ -284,19 +271,13 @@ int pim_assert_recv(struct interface *ifp, struct pim_neighbor *neigh, msg_metric.route_metric = pim_read_uint32_host(curr); - if (PIM_DEBUG_PIM_TRACE) { - char neigh_str[INET_ADDRSTRLEN]; - char source_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<neigh?>", src_addr, neigh_str, - sizeof(neigh_str)); - pim_inet4_dump("<src?>", msg_source_addr.u.prefix4, source_str, - sizeof(source_str)); + if (PIM_DEBUG_PIM_TRACE) zlog_debug( - "%s: from %s on %s: (S,G)=(%s,%pPAs) pref=%u metric=%u rpt_bit=%u", - __func__, neigh_str, ifp->name, source_str, &sg.grp, - msg_metric.metric_preference, msg_metric.route_metric, + "%s: from %pPAs on %s: (S,G)=(%pPAs,%pPAs) pref=%u metric=%u rpt_bit=%u", + __func__, &src_addr, ifp->name, &msg_source_addr, + &sg.grp, msg_metric.metric_preference, + msg_metric.route_metric, PIM_FORCE_BOOLEAN(msg_metric.rpt_bit_flag)); - } msg_metric.ip_address = src_addr; @@ -304,8 +285,7 @@ int pim_assert_recv(struct interface *ifp, struct pim_neighbor *neigh, assert(pim_ifp); ++pim_ifp->pim_ifstat_assert_recv; - return dispatch_assert(ifp, msg_source_addr.u.prefix4, sg.grp, - msg_metric); + return dispatch_assert(ifp, msg_source_addr, sg.grp, msg_metric); } /* @@ -354,7 +334,7 @@ int pim_assert_metric_match(const struct pim_assert_metric *m1, } int pim_assert_build_msg(uint8_t *pim_msg, int buf_size, struct interface *ifp, - struct in_addr group_addr, struct in_addr source_addr, + pim_addr group_addr, pim_addr source_addr, uint32_t metric_preference, uint32_t route_metric, uint32_t rpt_bit_flag) { @@ -368,28 +348,21 @@ int pim_assert_build_msg(uint8_t *pim_msg, int buf_size, struct interface *ifp, /* Encode group */ remain = buf_pastend - pim_msg_curr; - pim_msg_curr = pim_msg_addr_encode_ipv4_group(pim_msg_curr, group_addr); + pim_msg_curr = pim_msg_addr_encode_group(pim_msg_curr, group_addr); if (!pim_msg_curr) { - char group_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<grp?>", group_addr, group_str, - sizeof(group_str)); zlog_warn( - "%s: failure encoding group address %s: space left=%d", - __func__, group_str, remain); + "%s: failure encoding group address %pPA: space left=%d", + __func__, &group_addr, remain); return -1; } /* Encode source */ remain = buf_pastend - pim_msg_curr; - pim_msg_curr = - pim_msg_addr_encode_ipv4_ucast(pim_msg_curr, source_addr); + pim_msg_curr = pim_msg_addr_encode_ucast(pim_msg_curr, source_addr); if (!pim_msg_curr) { - char source_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", source_addr, source_str, - sizeof(source_str)); zlog_warn( - "%s: failure encoding source address %s: space left=%d", - __func__, source_str, remain); + "%s: failure encoding source address %pPA: space left=%d", + __func__, &source_addr, remain); return -2; } diff --git a/pimd/pim_assert.h b/pimd/pim_assert.h index a149fb176e..22bab67c59 100644 --- a/pimd/pim_assert.h +++ b/pimd/pim_assert.h @@ -59,7 +59,7 @@ void pim_ifassert_winner_set(struct pim_ifchannel *ch, struct pim_assert_metric winner_metric); int pim_assert_recv(struct interface *ifp, struct pim_neighbor *neigh, - struct in_addr src_addr, uint8_t *buf, int buf_size); + pim_addr src_addr, uint8_t *buf, int buf_size); int pim_assert_metric_better(const struct pim_assert_metric *m1, const struct pim_assert_metric *m2); @@ -67,7 +67,7 @@ int pim_assert_metric_match(const struct pim_assert_metric *m1, const struct pim_assert_metric *m2); int pim_assert_build_msg(uint8_t *pim_msg, int buf_size, struct interface *ifp, - struct in_addr group_addr, struct in_addr source_addr, + pim_addr group_addr, pim_addr source_addr, uint32_t metric_preference, uint32_t route_metric, uint32_t rpt_bit_flag); diff --git a/pimd/pim_bfd.c b/pimd/pim_bfd.c index 31f672bb80..3e3021dc4d 100644 --- a/pimd/pim_bfd.c +++ b/pimd/pim_bfd.c @@ -94,7 +94,11 @@ void pim_bfd_info_nbr_create(struct pim_interface *pim_ifp, bfd_sess_set_timers( neigh->bfd_session, pim_ifp->bfd_config.detection_multiplier, pim_ifp->bfd_config.min_rx, pim_ifp->bfd_config.min_tx); +#if PIM_IPV == 4 || !defined(PIM_V6_TEMP_BREAK) bfd_sess_set_ipv4_addrs(neigh->bfd_session, NULL, &neigh->source_addr); +#else + bfd_sess_set_ipv6_addrs(neigh->bfd_session, NULL, &neigh->source_addr); +#endif bfd_sess_set_interface(neigh->bfd_session, neigh->interface->name); bfd_sess_set_vrf(neigh->bfd_session, neigh->interface->vrf->vrf_id); bfd_sess_set_profile(neigh->bfd_session, pim_ifp->bfd_config.profile); diff --git a/pimd/pim_bsm.c b/pimd/pim_bsm.c index 4214790476..0b993ec05e 100644 --- a/pimd/pim_bsm.c +++ b/pimd/pim_bsm.c @@ -667,10 +667,7 @@ void pim_bsm_clear(struct pim_instance *pim) struct prefix grp; struct rp_info *trp_info; - grp.family = AF_INET; - grp.prefixlen = IPV4_MAX_BITLEN; - grp.u.prefix4 = up->sg.grp; - + pim_addr_to_prefix(&grp, up->sg.grp); trp_info = pim_rp_find_match_group(pim, &grp); /* RP not found for the group grp */ @@ -690,7 +687,7 @@ void pim_bsm_clear(struct pim_instance *pim) } static bool pim_bsm_send_intf(uint8_t *buf, int len, struct interface *ifp, - struct in_addr dst_addr) + pim_addr dst_addr) { struct pim_interface *pim_ifp; @@ -723,8 +720,7 @@ static bool pim_bsm_send_intf(uint8_t *buf, int len, struct interface *ifp, } static bool pim_bsm_frag_send(uint8_t *buf, uint32_t len, struct interface *ifp, - uint32_t pim_mtu, struct in_addr dst_addr, - bool no_fwd) + uint32_t pim_mtu, pim_addr dst_addr, bool no_fwd) { struct bsmmsg_grpinfo *grpinfo, *curgrp; uint8_t *firstgrp_ptr; @@ -895,7 +891,7 @@ static void pim_bsm_fwd_whole_sz(struct pim_instance *pim, uint8_t *buf, { struct interface *ifp; struct pim_interface *pim_ifp; - struct in_addr dst_addr; + pim_addr dst_addr; uint32_t pim_mtu; bool no_fwd = false; bool ret = false; @@ -942,7 +938,7 @@ static void pim_bsm_fwd_whole_sz(struct pim_instance *pim, uint8_t *buf, bool pim_bsm_new_nbr_fwd(struct pim_neighbor *neigh, struct interface *ifp) { - struct in_addr dst_addr; + pim_addr dst_addr; struct pim_interface *pim_ifp; struct bsm_scope *scope; struct bsm_frag *bsfrag; @@ -951,17 +947,14 @@ bool pim_bsm_new_nbr_fwd(struct pim_neighbor *neigh, struct interface *ifp) bool no_fwd = true; bool ret = false; - if (PIM_DEBUG_BSM) { - pim_inet4_dump("<src?>", neigh->source_addr, neigh_src_str, - sizeof(neigh_src_str)); - zlog_debug("%s: New neighbor %s seen on %s", __func__, - neigh_src_str, ifp->name); - } + if (PIM_DEBUG_BSM) + zlog_debug("%s: New neighbor %pPA seen on %s", __func__, + &neigh->source_addr, ifp->name); pim_ifp = ifp->info; /* DR only forwards BSM packet */ - if (pim_ifp->pim_dr_addr.s_addr == pim_ifp->primary_address.s_addr) { + if (!pim_addr_cmp(pim_ifp->pim_dr_addr, pim_ifp->primary_address)) { if (PIM_DEBUG_BSM) zlog_debug( "%s: It is not DR, so don't forward BSM packet", diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 2baaca1c9f..83ba74f69f 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -2427,9 +2427,9 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty, if (!up->t_join_timer && up->rpf.source_nexthop.interface) { struct pim_neighbor *nbr; - nbr = pim_neighbor_find( + nbr = pim_neighbor_find_prefix( up->rpf.source_nexthop.interface, - up->rpf.rpf_addr.u.prefix4); + &up->rpf.rpf_addr); if (nbr) pim_time_timer_to_hhmmss(join_timer, sizeof(join_timer), @@ -3488,15 +3488,24 @@ static void igmp_show_group_retransmission(struct pim_instance *pim, } /* scan interfaces */ } -static void igmp_show_sources(struct pim_instance *pim, struct vty *vty) +static void igmp_show_sources(struct pim_instance *pim, struct vty *vty, + bool uj) { struct interface *ifp; time_t now; + json_object *json = NULL; + json_object *json_iface = NULL; + json_object *json_group = NULL; + json_object *json_source = NULL; + json_object *json_sources = NULL; now = pim_time_monotonic_sec(); - vty_out(vty, - "Interface Group Source Timer Fwd Uptime \n"); + if (uj) + json = json_object_new_object(); + else + vty_out(vty, + "Interface Address Group Source Timer Fwd Uptime \n"); /* scan interfaces */ FOR_ALL_INTERFACES (pim->vrf, ifp) { @@ -3533,17 +3542,70 @@ static void igmp_show_sources(struct pim_instance *pim, struct vty *vty) pim_time_uptime(uptime, sizeof(uptime), now - src->source_creation); - vty_out(vty, "%-16s %-15s %-15s %5s %3s %8s\n", - ifp->name, group_str, source_str, mmss, - IGMP_SOURCE_TEST_FORWARDING( - src->source_flags) - ? "Y" - : "N", - uptime); + if (uj) { + json_object_object_get_ex( + json, ifp->name, &json_iface); + if (!json_iface) { + json_iface = + json_object_new_object(); + json_object_string_add( + json_iface, "name", + ifp->name); + json_object_object_add( + json, ifp->name, + json_iface); + } + json_object_object_get_ex(json_iface, + group_str, + &json_group); + + if (!json_group) { + json_group = + json_object_new_object(); + json_object_string_add( + json_group, "group", + group_str); + json_object_object_add( + json_iface, group_str, + json_group); + json_sources = + json_object_new_array(); + json_object_object_add( + json_group, "sources", + json_sources); + } + json_source = json_object_new_object(); + json_object_string_add(json_source, + "source", + source_str); + json_object_string_add(json_source, + "timer", mmss); + json_object_boolean_add( + json_source, "forwarded", + IGMP_SOURCE_TEST_FORWARDING( + src->source_flags)); + json_object_string_add( + json_source, "uptime", uptime); + json_object_array_add(json_sources, + json_source); + + } else { + vty_out(vty, + "%-16s %-15s %-15s %5s %3s %8s\n", + ifp->name, group_str, + source_str, mmss, + IGMP_SOURCE_TEST_FORWARDING( + src->source_flags) + ? "Y" + : "N", + uptime); + } } /* scan group sources */ } /* scan igmp groups */ } /* scan interfaces */ + if (uj) + vty_json(vty, json); } static void igmp_show_source_retransmission(struct pim_instance *pim, @@ -4189,12 +4251,13 @@ DEFUN (show_ip_igmp_groups_retransmissions, DEFUN (show_ip_igmp_sources, show_ip_igmp_sources_cmd, - "show ip igmp [vrf NAME] sources", + "show ip igmp [vrf NAME] sources [json]", SHOW_STR IP_STR IGMP_STR VRF_CMD_HELP_STR - IGMP_SOURCE_STR) + IGMP_SOURCE_STR + JSON_STR) { int idx = 2; struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); @@ -4202,7 +4265,7 @@ DEFUN (show_ip_igmp_sources, if (!vrf) return CMD_WARNING; - igmp_show_sources(vrf->info, vty); + igmp_show_sources(vrf->info, vty, use_json(argc, argv)); return CMD_SUCCESS; } @@ -8174,7 +8237,8 @@ DEFPY_HIDDEN (interface_ip_igmp_query_generate, "IGMP version number\n") { VTY_DECLVAR_CONTEXT(interface, ifp); - int igmp_version = 2; + int igmp_version; + struct pim_interface *pim_ifp = ifp->info; if (!ifp->info) { vty_out(vty, "IGMP/PIM is not enabled on the interface %s\n", @@ -8182,6 +8246,9 @@ DEFPY_HIDDEN (interface_ip_igmp_query_generate, return CMD_WARNING_CONFIG_FAILED; } + /* It takes the igmp version configured on the interface as default */ + igmp_version = pim_ifp->igmp_version; + if (argc > 3) igmp_version = atoi(argv[4]->arg); diff --git a/pimd/pim_hello.c b/pimd/pim_hello.c index 45ea6a9562..fe4f10aa6a 100644 --- a/pimd/pim_hello.c +++ b/pimd/pim_hello.c @@ -33,81 +33,62 @@ #include "pim_upstream.h" #include "pim_bsm.h" -static void on_trace(const char *label, struct interface *ifp, - struct in_addr src) +static void on_trace(const char *label, struct interface *ifp, pim_addr src) { - if (PIM_DEBUG_PIM_TRACE) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src, src_str, sizeof(src_str)); - zlog_debug("%s: from %s on %s", label, src_str, ifp->name); - } + if (PIM_DEBUG_PIM_TRACE) + zlog_debug("%s: from %pPAs on %s", label, &src, ifp->name); } static void tlv_trace_bool(const char *label, const char *tlv_name, - const char *ifname, struct in_addr src_addr, - int isset, int value) + const char *ifname, pim_addr src_addr, int isset, + int value) { - if (isset) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); + if (isset) zlog_debug( - "%s: PIM hello option from %s on interface %s: %s=%d", - label, src_str, ifname, tlv_name, value); - } + "%s: PIM hello option from %pPAs on interface %s: %s=%d", + label, &src_addr, ifname, tlv_name, value); } static void tlv_trace_uint16(const char *label, const char *tlv_name, - const char *ifname, struct in_addr src_addr, - int isset, uint16_t value) + const char *ifname, pim_addr src_addr, int isset, + uint16_t value) { - if (isset) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); + if (isset) zlog_debug( - "%s: PIM hello option from %s on interface %s: %s=%u", - label, src_str, ifname, tlv_name, value); - } + "%s: PIM hello option from %pPAs on interface %s: %s=%u", + label, &src_addr, ifname, tlv_name, value); } static void tlv_trace_uint32(const char *label, const char *tlv_name, - const char *ifname, struct in_addr src_addr, - int isset, uint32_t value) + const char *ifname, pim_addr src_addr, int isset, + uint32_t value) { - if (isset) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); + if (isset) zlog_debug( - "%s: PIM hello option from %s on interface %s: %s=%u", - label, src_str, ifname, tlv_name, value); - } + "%s: PIM hello option from %pPAs on interface %s: %s=%u", + label, &src_addr, ifname, tlv_name, value); } static void tlv_trace_uint32_hex(const char *label, const char *tlv_name, - const char *ifname, struct in_addr src_addr, + const char *ifname, pim_addr src_addr, int isset, uint32_t value) { - if (isset) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); + if (isset) zlog_debug( - "%s: PIM hello option from %s on interface %s: %s=%08x", - label, src_str, ifname, tlv_name, value); - } + "%s: PIM hello option from %pPAs on interface %s: %s=%08x", + label, &src_addr, ifname, tlv_name, value); } static void tlv_trace_list(const char *label, const char *tlv_name, - const char *ifname, struct in_addr src_addr, - int isset, struct list *addr_list) + const char *ifname, pim_addr src_addr, int isset, + struct list *addr_list) { - if (isset) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); + if (isset) zlog_debug( - "%s: PIM hello option from %s on interface %s: %s size=%d list=%p", - label, src_str, ifname, tlv_name, + "%s: PIM hello option from %pPAs on interface %s: %s size=%d list=%p", + label, &src_addr, ifname, tlv_name, addr_list ? ((int)listcount(addr_list)) : -1, (void *)addr_list); - } } #define FREE_ADDR_LIST \ @@ -121,8 +102,8 @@ static void tlv_trace_list(const char *label, const char *tlv_name, return (code); \ } -int pim_hello_recv(struct interface *ifp, struct in_addr src_addr, - uint8_t *tlv_buf, int tlv_buf_size) +int pim_hello_recv(struct interface *ifp, pim_addr src_addr, uint8_t *tlv_buf, + int tlv_buf_size) { struct pim_interface *pim_ifp; struct pim_neighbor *neigh; @@ -158,15 +139,11 @@ int pim_hello_recv(struct interface *ifp, struct in_addr src_addr, int remain = tlv_pastend - tlv_curr; if (remain < PIM_TLV_MIN_SIZE) { - if (PIM_DEBUG_PIM_HELLO) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, - sizeof(src_str)); + if (PIM_DEBUG_PIM_HELLO) zlog_debug( - "%s: short PIM hello TLV size=%d < min=%d from %s on interface %s", + "%s: short PIM hello TLV size=%d < min=%d from %pPAs on interface %s", __func__, remain, PIM_TLV_MIN_SIZE, - src_str, ifp->name); - } + &src_addr, ifp->name); FREE_ADDR_LIST_THEN_RETURN(-1); } @@ -176,28 +153,20 @@ int pim_hello_recv(struct interface *ifp, struct in_addr src_addr, tlv_curr += PIM_TLV_LENGTH_SIZE; if ((tlv_curr + option_len) > tlv_pastend) { - if (PIM_DEBUG_PIM_HELLO) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, - sizeof(src_str)); + if (PIM_DEBUG_PIM_HELLO) zlog_debug( - "%s: long PIM hello TLV type=%d length=%d > left=%td from %s on interface %s", + "%s: long PIM hello TLV type=%d length=%d > left=%td from %pPAs on interface %s", __func__, option_type, option_len, - tlv_pastend - tlv_curr, src_str, + tlv_pastend - tlv_curr, &src_addr, ifp->name); - } FREE_ADDR_LIST_THEN_RETURN(-2); } - if (PIM_DEBUG_PIM_HELLO) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, - sizeof(src_str)); + if (PIM_DEBUG_PIM_HELLO) zlog_debug( - "%s: parse left_size=%d: PIM hello TLV type=%d length=%d from %s on %s", + "%s: parse left_size=%d: PIM hello TLV type=%d length=%d from %pPAs on %s", __func__, remain, option_type, option_len, - src_str, ifp->name); - } + &src_addr, ifp->name); switch (option_type) { case PIM_MSG_OPTION_TYPE_HOLDTIME: @@ -242,26 +211,18 @@ int pim_hello_recv(struct interface *ifp, struct in_addr src_addr, } break; case PIM_MSG_OPTION_TYPE_DM_STATE_REFRESH: - if (PIM_DEBUG_PIM_HELLO) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, - sizeof(src_str)); + if (PIM_DEBUG_PIM_HELLO) zlog_debug( - "%s: ignoring PIM hello dense-mode state refresh TLV option type=%d length=%d from %s on interface %s", + "%s: ignoring PIM hello dense-mode state refresh TLV option type=%d length=%d from %pPAs on interface %s", __func__, option_type, option_len, - src_str, ifp->name); - } + &src_addr, ifp->name); break; default: - if (PIM_DEBUG_PIM_HELLO) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, - sizeof(src_str)); + if (PIM_DEBUG_PIM_HELLO) zlog_debug( - "%s: ignoring unknown PIM hello TLV type=%d length=%d from %s on interface %s", + "%s: ignoring unknown PIM hello TLV type=%d length=%d from %pPAs on interface %s", __func__, option_type, option_len, - src_str, ifp->name); - } + &src_addr, ifp->name); } tlv_curr += option_len; @@ -310,14 +271,10 @@ int pim_hello_recv(struct interface *ifp, struct in_addr src_addr, } if (!PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME)) { - if (PIM_DEBUG_PIM_HELLO) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, - sizeof(src_str)); + if (PIM_DEBUG_PIM_HELLO) zlog_debug( - "%s: PIM hello missing holdtime from %s on interface %s", - __func__, src_str, ifp->name); - } + "%s: PIM hello missing holdtime from %pPAs on interface %s", + __func__, &src_addr, ifp->name); } /* @@ -335,14 +292,10 @@ int pim_hello_recv(struct interface *ifp, struct in_addr src_addr, hello_option_dr_priority, hello_option_generation_id, hello_option_addr_list, PIM_NEIGHBOR_SEND_DELAY); if (!neigh) { - if (PIM_DEBUG_PIM_HELLO) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, - sizeof(src_str)); + if (PIM_DEBUG_PIM_HELLO) zlog_warn( - "%s: failure creating PIM neighbor %s on interface %s", - __func__, src_str, ifp->name); - } + "%s: failure creating PIM neighbor %pPAs on interface %s", + __func__, &src_addr, ifp->name); FREE_ADDR_LIST_THEN_RETURN(-8); } /* Forward BSM if required */ @@ -368,16 +321,12 @@ int pim_hello_recv(struct interface *ifp, struct in_addr src_addr, || (hello_option_generation_id != neigh->generation_id)) { /* GenID mismatch, then replace neighbor */ - if (PIM_DEBUG_PIM_HELLO) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, - sizeof(src_str)); + if (PIM_DEBUG_PIM_HELLO) zlog_debug( - "%s: GenId mismatch new=%08x old=%08x: replacing neighbor %s on %s", + "%s: GenId mismatch new=%08x old=%08x: replacing neighbor %pPAs on %s", __func__, hello_option_generation_id, - neigh->generation_id, src_str, + neigh->generation_id, &src_addr, ifp->name); - } pim_upstream_rpf_genid_changed(pim_ifp->pim, neigh->source_addr); @@ -392,15 +341,10 @@ int pim_hello_recv(struct interface *ifp, struct in_addr src_addr, hello_option_addr_list, PIM_NEIGHBOR_SEND_NOW); if (!neigh) { - if (PIM_DEBUG_PIM_HELLO) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, - src_str, - sizeof(src_str)); + if (PIM_DEBUG_PIM_HELLO) zlog_debug( - "%s: failure re-creating PIM neighbor %s on interface %s", - __func__, src_str, ifp->name); - } + "%s: failure re-creating PIM neighbor %pPAs on interface %s", + __func__, &src_addr, ifp->name); FREE_ADDR_LIST_THEN_RETURN(-9); } /* Forward BSM if required */ diff --git a/pimd/pim_hello.h b/pimd/pim_hello.h index df41f97d9e..56084e06d2 100644 --- a/pimd/pim_hello.h +++ b/pimd/pim_hello.h @@ -24,8 +24,8 @@ #include "if.h" -int pim_hello_recv(struct interface *ifp, struct in_addr src_addr, - uint8_t *tlv_buf, int tlv_buf_size); +int pim_hello_recv(struct interface *ifp, pim_addr src_addr, uint8_t *tlv_buf, + int tlv_buf_size); int pim_hello_build_tlv(struct interface *ifp, uint8_t *tlv_buf, int tlv_buf_size, uint16_t holdtime, diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 3f138e22e5..57fe97816e 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -193,7 +193,6 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool igmp, bool pim, void pim_if_delete(struct interface *ifp) { struct pim_interface *pim_ifp; - struct pim_ifchannel *ch; assert(ifp); pim_ifp = ifp->info; @@ -218,13 +217,6 @@ void pim_if_delete(struct interface *ifp) list_delete(&pim_ifp->sec_addr_list); XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist); - - while (!RB_EMPTY(pim_ifchannel_rb, &pim_ifp->ifchannel_rb)) { - ch = RB_ROOT(pim_ifchannel_rb, &pim_ifp->ifchannel_rb); - - pim_ifchannel_delete(ch); - } - XFREE(MTYPE_PIM_INTERFACE, pim_ifp); ifp->info = NULL; @@ -299,27 +291,20 @@ static int detect_primary_address_change(struct interface *ifp, const char *caller) { struct pim_interface *pim_ifp = ifp->info; - struct in_addr new_prim_addr; + pim_addr new_prim_addr; int changed; if (force_prim_as_any) - new_prim_addr.s_addr = INADDR_ANY; + new_prim_addr = PIMADDR_ANY; else new_prim_addr = pim_find_primary_addr(ifp); - changed = new_prim_addr.s_addr != pim_ifp->primary_address.s_addr; + changed = pim_addr_cmp(new_prim_addr, pim_ifp->primary_address); - if (PIM_DEBUG_ZEBRA) { - char new_prim_str[INET_ADDRSTRLEN]; - char old_prim_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<new?>", new_prim_addr, new_prim_str, - sizeof(new_prim_str)); - pim_inet4_dump("<old?>", pim_ifp->primary_address, old_prim_str, - sizeof(old_prim_str)); - zlog_debug("%s: old=%s new=%s on interface %s: %s", __func__, - old_prim_str, new_prim_str, ifp->name, - changed ? "changed" : "unchanged"); - } + if (PIM_DEBUG_ZEBRA) + zlog_debug("%s: old=%pPA new=%pPA on interface %s: %s", + __func__, &pim_ifp->primary_address, &new_prim_addr, + ifp->name, changed ? "changed" : "unchanged"); if (changed) { /* Before updating pim_ifp send Hello time with 0 hold time */ @@ -401,19 +386,18 @@ static int pim_sec_addr_update(struct interface *ifp) } for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { - struct prefix *p = ifc->address; + pim_addr addr = pim_addr_from_prefix(ifc->address); - if (p->u.prefix4.s_addr == INADDR_ANY) { + if (pim_addr_is_any(addr)) continue; - } - if (pim_ifp->primary_address.s_addr == p->u.prefix4.s_addr) { + if (!pim_addr_cmp(addr, pim_ifp->primary_address)) { /* don't add the primary address into the secondary * address list */ continue; } - if (pim_sec_addr_add(pim_ifp, p)) { + if (pim_sec_addr_add(pim_ifp, ifc->address)) { changed = 1; } } @@ -480,7 +464,7 @@ static void detect_address_change(struct interface *ifp, int force_prim_as_any, * address change on all of them when the lo address changes */ } -int pim_update_source_set(struct interface *ifp, struct in_addr source) +int pim_update_source_set(struct interface *ifp, pim_addr source) { struct pim_interface *pim_ifp = ifp->info; @@ -488,7 +472,7 @@ int pim_update_source_set(struct interface *ifp, struct in_addr source) return PIM_IFACE_NOT_FOUND; } - if (pim_ifp->update_source.s_addr == source.s_addr) { + if (!pim_addr_cmp(pim_ifp->update_source, source)) { return PIM_UPDATE_SOURCE_DUP; } @@ -827,11 +811,10 @@ void pim_if_addr_del_all_igmp(struct interface *ifp) } } -struct in_addr pim_find_primary_addr(struct interface *ifp) +pim_addr pim_find_primary_addr(struct interface *ifp) { struct connected *ifc; struct listnode *node; - struct in_addr addr = {0}; int v4_addrs = 0; int v6_addrs = 0; struct pim_interface *pim_ifp = ifp->info; @@ -841,28 +824,35 @@ struct in_addr pim_find_primary_addr(struct interface *ifp) } for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { - struct prefix *p = ifc->address; + pim_addr addr; - if (p->family != AF_INET) { + switch (ifc->address->family) { + case AF_INET: + v4_addrs++; + break; + case AF_INET6: v6_addrs++; + break; + default: continue; } - if (p->u.prefix4.s_addr == INADDR_ANY) { - zlog_warn( - "%s: null IPv4 address connected to interface %s", - __func__, ifp->name); + if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)) continue; - } - v4_addrs++; - - if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)) + if (ifc->address->family != PIM_AF) continue; - return p->u.prefix4; + addr = pim_addr_from_prefix(ifc->address); + +#if PIM_IPV == 6 + if (!IN6_IS_ADDR_LINKLOCAL(&addr)) + continue; +#endif + return addr; } +#if PIM_IPV == 4 /* * If we have no v4_addrs and v6 is configured * We probably are using unnumbered @@ -882,10 +872,8 @@ struct in_addr pim_find_primary_addr(struct interface *ifp) if (lo_ifp && (lo_ifp != ifp)) return pim_find_primary_addr(lo_ifp); } - - addr.s_addr = PIM_NET_INADDR_ANY; - - return addr; +#endif + return PIMADDR_ANY; } static int pim_iface_next_vif_index(struct interface *ifp) @@ -1094,8 +1082,7 @@ uint16_t pim_if_jp_override_interval_msec(struct interface *ifp) router (Section 4.3.4). The primary IP address of a neighbor is the address that it uses as the source of its PIM Hello messages. */ -struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp, - struct in_addr addr) +struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp, pim_addr addr) { struct listnode *neighnode; struct pim_neighbor *neigh; @@ -1111,15 +1098,13 @@ struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp, return 0; } - p.family = AF_INET; - p.u.prefix4 = addr; - p.prefixlen = IPV4_MAX_BITLEN; + pim_addr_to_prefix(&p, addr); for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) { /* primary address ? */ - if (neigh->source_addr.s_addr == addr.s_addr) + if (!pim_addr_cmp(neigh->source_addr, addr)) return neigh; /* secondary address ? */ @@ -1127,13 +1112,10 @@ struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp, return neigh; } - if (PIM_DEBUG_PIM_TRACE) { - char addr_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); + if (PIM_DEBUG_PIM_TRACE) zlog_debug( - "%s: neighbor not found for address %s on interface %s", - __func__, addr_str, ifp->name); - } + "%s: neighbor not found for address %pPA on interface %s", + __func__, &addr, ifp->name); return NULL; } @@ -1383,8 +1365,7 @@ static void pim_if_igmp_join_del_all(struct interface *ifp) gone down (and may have come back up), and so we must assume it no longer knows it was the winner. */ -void pim_if_assert_on_neighbor_down(struct interface *ifp, - struct in_addr neigh_addr) +void pim_if_assert_on_neighbor_down(struct interface *ifp, pim_addr neigh_addr) { struct pim_interface *pim_ifp; struct pim_ifchannel *ch; @@ -1397,7 +1378,7 @@ void pim_if_assert_on_neighbor_down(struct interface *ifp, if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER) continue; /* Dead neighbor was winner ? */ - if (ch->ifassert_winner.s_addr != neigh_addr.s_addr) + if (pim_addr_cmp(ch->ifassert_winner, neigh_addr)) continue; assert_action_a5(ch); @@ -1473,7 +1454,7 @@ void pim_if_create_pimreg(struct pim_instance *pim) } } -struct prefix *pim_if_connected_to_source(struct interface *ifp, struct in_addr src) +struct prefix *pim_if_connected_to_source(struct interface *ifp, pim_addr src) { struct listnode *cnode; struct connected *c; @@ -1482,12 +1463,10 @@ struct prefix *pim_if_connected_to_source(struct interface *ifp, struct in_addr if (!ifp) return NULL; - p.family = AF_INET; - p.u.prefix4 = src; - p.prefixlen = IPV4_MAX_BITLEN; + pim_addr_to_prefix(&p, src); for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) { - if (c->address->family != AF_INET) + if (c->address->family != PIM_AF) continue; if (prefix_match(c->address, &p)) return c->address; diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h index 1ddf743619..00ec8e7427 100644 --- a/pimd/pim_iface.h +++ b/pimd/pim_iface.h @@ -59,7 +59,8 @@ #define PIM_IF_DONT_PIM_CAN_DISABLE_JOIN_SUPPRESSION(options) \ ((options) &= ~PIM_IF_MASK_PIM_CAN_DISABLE_JOIN_SUPPRESSION) -#define PIM_I_am_DR(pim_ifp) (pim_ifp)->pim_dr_addr.s_addr == (pim_ifp)->primary_address.s_addr +#define PIM_I_am_DR(pim_ifp) \ + !pim_addr_cmp((pim_ifp)->pim_dr_addr, (pim_ifp)->primary_address) #define PIM_I_am_DualActive(pim_ifp) (pim_ifp)->activeactive == true /* Macros for interface flags */ @@ -225,13 +226,12 @@ int pim_if_lan_delay_enabled(struct interface *ifp); uint16_t pim_if_effective_propagation_delay_msec(struct interface *ifp); uint16_t pim_if_effective_override_interval_msec(struct interface *ifp); uint16_t pim_if_jp_override_interval_msec(struct interface *ifp); -struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp, - struct in_addr addr); +struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp, pim_addr addr); long pim_if_t_suppressed_msec(struct interface *ifp); int pim_if_t_override_msec(struct interface *ifp); -struct in_addr pim_find_primary_addr(struct interface *ifp); +pim_addr pim_find_primary_addr(struct interface *ifp); ferr_r pim_if_igmp_join_add(struct interface *ifp, struct in_addr group_addr, struct in_addr source_addr); @@ -240,8 +240,7 @@ int pim_if_igmp_join_del(struct interface *ifp, struct in_addr group_addr, void pim_if_update_could_assert(struct interface *ifp); -void pim_if_assert_on_neighbor_down(struct interface *ifp, - struct in_addr neigh_addr); +void pim_if_assert_on_neighbor_down(struct interface *ifp, pim_addr neigh_addr); void pim_if_rpf_interface_changed(struct interface *old_rpf_ifp, struct pim_upstream *up); @@ -252,8 +251,8 @@ void pim_if_update_assert_tracking_desired(struct interface *ifp); void pim_if_create_pimreg(struct pim_instance *pim); -struct prefix *pim_if_connected_to_source(struct interface *ifp, struct in_addr src); -int pim_update_source_set(struct interface *ifp, struct in_addr source); +struct prefix *pim_if_connected_to_source(struct interface *ifp, pim_addr src); +int pim_update_source_set(struct interface *ifp, pim_addr source); bool pim_if_is_vrf_device(struct interface *ifp); diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index 9248177724..a613c89b7e 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -423,11 +423,9 @@ const char *pim_ifchannel_ifassert_name(enum pim_ifassert_state ifassert_state) */ void reset_ifassert_state(struct pim_ifchannel *ch) { - struct in_addr any = {.s_addr = INADDR_ANY}; - THREAD_OFF(ch->t_ifassert_timer); - pim_ifassert_winner_set(ch, PIM_IFASSERT_NOINFO, any, + pim_ifassert_winner_set(ch, PIM_IFASSERT_NOINFO, PIMADDR_ANY, router->infinite_assert_metric); } @@ -587,7 +585,7 @@ struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp, pim_sgaddr *sg, ch->ifassert_my_metric = pim_macro_ch_my_assert_metric_eval(ch); ch->ifassert_winner_metric = pim_macro_ch_my_assert_metric_eval(ch); - ch->ifassert_winner.s_addr = INADDR_ANY; + ch->ifassert_winner = PIMADDR_ANY; /* Assert state */ ch->t_ifassert_timer = NULL; @@ -688,8 +686,8 @@ static int on_ifjoin_prune_pending_timer(struct thread *t) struct pim_rpf rpf; rpf.source_nexthop.interface = ifp; - rpf.rpf_addr.u.prefix4 = - pim_ifp->primary_address; + pim_addr_to_prefix(&rpf.rpf_addr, + pim_ifp->primary_address); pim_jp_agg_single_upstream_send( &rpf, ch->upstream, 0); } @@ -733,11 +731,12 @@ static int on_ifjoin_prune_pending_timer(struct thread *t) } static void check_recv_upstream(int is_join, struct interface *recv_ifp, - struct in_addr upstream, pim_sgaddr *sg, + pim_addr upstream, pim_sgaddr *sg, uint8_t source_flags, int holdtime) { struct pim_upstream *up; struct pim_interface *pim_ifp = recv_ifp->info; + pim_addr rpf_addr; /* Upstream (S,G) in Joined state ? */ up = pim_upstream_find(pim_ifp->pim, sg); @@ -755,16 +754,13 @@ static void check_recv_upstream(int is_join, struct interface *recv_ifp, return; } + rpf_addr = pim_addr_from_prefix(&up->rpf.rpf_addr); + /* upstream directed to RPF'(S,G) ? */ - if (upstream.s_addr != up->rpf.rpf_addr.u.prefix4.s_addr) { - char up_str[INET_ADDRSTRLEN]; - char rpf_str[PREFIX_STRLEN]; - pim_inet4_dump("<up?>", upstream, up_str, sizeof(up_str)); - pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_str, - sizeof(rpf_str)); + if (pim_addr_cmp(upstream, rpf_addr)) { zlog_warn( - "%s %s: (S,G)=%s upstream=%s not directed to RPF'(S,G)=%s on interface %s", - __FILE__, __func__, up->sg_str, up_str, rpf_str, + "%s %s: (S,G)=%s upstream=%pPAs not directed to RPF'(S,G)=%pPAs on interface %s", + __FILE__, __func__, up->sg_str, &upstream, &rpf_addr, recv_ifp->name); return; } @@ -798,7 +794,7 @@ static void check_recv_upstream(int is_join, struct interface *recv_ifp, } static int nonlocal_upstream(int is_join, struct interface *recv_ifp, - struct in_addr upstream, pim_sgaddr *sg, + pim_addr upstream, pim_sgaddr *sg, uint8_t source_flags, uint16_t holdtime) { struct pim_interface *recv_pim_ifp; @@ -807,18 +803,16 @@ static int nonlocal_upstream(int is_join, struct interface *recv_ifp, recv_pim_ifp = recv_ifp->info; assert(recv_pim_ifp); - is_local = (upstream.s_addr == recv_pim_ifp->primary_address.s_addr); + is_local = !pim_addr_cmp(upstream, recv_pim_ifp->primary_address); if (is_local) return 0; - if (PIM_DEBUG_PIM_TRACE_DETAIL) { - char up_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str)); - zlog_warn("%s: recv %s (S,G)=%pSG to non-local upstream=%s on %s", - __func__, is_join ? "join" : "prune", - sg, up_str, recv_ifp->name); - } + if (PIM_DEBUG_PIM_TRACE_DETAIL) + zlog_warn( + "%s: recv %s (S,G)=%pSG to non-local upstream=%pPAs on %s", + __func__, is_join ? "join" : "prune", sg, &upstream, + recv_ifp->name); /* * Since recv upstream addr was not directed to our primary @@ -851,8 +845,8 @@ static void pim_ifchannel_ifjoin_handler(struct pim_ifchannel *ch, } -void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr, - struct in_addr upstream, pim_sgaddr *sg, +void pim_ifchannel_join_add(struct interface *ifp, pim_addr neigh_addr, + pim_addr upstream, pim_sgaddr *sg, uint8_t source_flags, uint16_t holdtime) { struct pim_interface *pim_ifp; @@ -883,11 +877,8 @@ void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr, address of the join message is our primary address. */ if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) { - char neigh_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<neigh?>", neigh_addr, neigh_str, - sizeof(neigh_str)); - zlog_warn("%s: Assert Loser recv Join%s from %s on %s", - __func__, ch->sg_str, neigh_str, ifp->name); + zlog_warn("%s: Assert Loser recv Join%s from %pI4 on %s", + __func__, ch->sg_str, &neigh_addr, ifp->name); assert_action_a5(ch); } @@ -1016,7 +1007,7 @@ void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr, } } -void pim_ifchannel_prune(struct interface *ifp, struct in_addr upstream, +void pim_ifchannel_prune(struct interface *ifp, pim_addr upstream, pim_sgaddr *sg, uint8_t source_flags, uint16_t holdtime) { @@ -1235,10 +1226,8 @@ int pim_ifchannel_local_membership_add(struct interface *ifp, pim_sgaddr *sg, struct prefix_list *plist = prefix_list_lookup( AFI_IP, pim->spt.plist); struct prefix g; - g.family = AF_INET; - g.prefixlen = IPV4_MAX_BITLEN; - g.u.prefix4 = up->sg.grp; + pim_addr_to_prefix(&g, up->sg.grp); if (prefix_list_apply(plist, &g) == PREFIX_DENY) { pim_channel_add_oif( @@ -1368,23 +1357,17 @@ void pim_ifchannel_update_my_assert_metric(struct pim_ifchannel *ch) if (pim_assert_metric_match(&my_metric_new, &ch->ifassert_my_metric)) return; - if (PIM_DEBUG_PIM_EVENTS) { - char old_addr_str[INET_ADDRSTRLEN]; - char new_addr_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<old_addr?>", ch->ifassert_my_metric.ip_address, - old_addr_str, sizeof(old_addr_str)); - pim_inet4_dump("<new_addr?>", my_metric_new.ip_address, - new_addr_str, sizeof(new_addr_str)); + if (PIM_DEBUG_PIM_EVENTS) zlog_debug( - "%s: my_assert_metric(%pPAs,%pPAs,%s) changed from %u,%u,%u,%s to %u,%u,%u,%s", + "%s: my_assert_metric(%pPAs,%pPAs,%s) changed from %u,%u,%u,%pPAs to %u,%u,%u,%pPAs", __func__, &ch->sg.src, &ch->sg.grp, ch->interface->name, ch->ifassert_my_metric.rpt_bit_flag, ch->ifassert_my_metric.metric_preference, - ch->ifassert_my_metric.route_metric, old_addr_str, + ch->ifassert_my_metric.route_metric, + &ch->ifassert_my_metric.ip_address, my_metric_new.rpt_bit_flag, my_metric_new.metric_preference, - my_metric_new.route_metric, new_addr_str); - } + my_metric_new.route_metric, &my_metric_new.ip_address); ch->ifassert_my_metric = my_metric_new; diff --git a/pimd/pim_ifchannel.h b/pimd/pim_ifchannel.h index ab405202e3..0c5b6780d1 100644 --- a/pimd/pim_ifchannel.h +++ b/pimd/pim_ifchannel.h @@ -126,10 +126,10 @@ void pim_ifchannel_delete_on_noinfo(struct interface *ifp); struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp, pim_sgaddr *sg); struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp, pim_sgaddr *sg, uint8_t ch_flags, int up_flags); -void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr, - struct in_addr upstream, pim_sgaddr *sg, +void pim_ifchannel_join_add(struct interface *ifp, pim_addr neigh_addr, + pim_addr upstream, pim_sgaddr *sg, uint8_t source_flags, uint16_t holdtime); -void pim_ifchannel_prune(struct interface *ifp, struct in_addr upstream, +void pim_ifchannel_prune(struct interface *ifp, pim_addr upstream, pim_sgaddr *sg, uint8_t source_flags, uint16_t holdtime); int pim_ifchannel_local_membership_add(struct interface *ifp, pim_sgaddr *sg, diff --git a/pimd/pim_join.c b/pimd/pim_join.c index fa2d8d462b..51a3ceee15 100644 --- a/pimd/pim_join.c +++ b/pimd/pim_join.c @@ -54,23 +54,17 @@ static void on_trace(const char *label, struct interface *ifp, } static void recv_join(struct interface *ifp, struct pim_neighbor *neigh, - uint16_t holdtime, struct in_addr upstream, - pim_sgaddr *sg, uint8_t source_flags) + uint16_t holdtime, pim_addr upstream, pim_sgaddr *sg, + uint8_t source_flags) { struct pim_interface *pim_ifp = NULL; - if (PIM_DEBUG_PIM_TRACE) { - char up_str[INET_ADDRSTRLEN]; - char neigh_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str)); - pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, - sizeof(neigh_str)); - zlog_debug("%s: join (S,G)=%pSG rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s", - __func__, sg, - !!(source_flags & PIM_RPT_BIT_MASK), - !!(source_flags & PIM_WILDCARD_BIT_MASK), up_str, - holdtime, neigh_str, ifp->name); - } + if (PIM_DEBUG_PIM_TRACE) + zlog_debug( + "%s: join (S,G)=%pSG rpt=%d wc=%d upstream=%pPAs holdtime=%d from %pPA on %s", + __func__, sg, !!(source_flags & PIM_RPT_BIT_MASK), + !!(source_flags & PIM_WILDCARD_BIT_MASK), &upstream, + holdtime, &neigh->source_addr, ifp->name); pim_ifp = ifp->info; assert(pim_ifp); @@ -84,6 +78,7 @@ static void recv_join(struct interface *ifp, struct pim_neighbor *neigh, if ((source_flags & PIM_RPT_BIT_MASK) && (source_flags & PIM_WILDCARD_BIT_MASK)) { struct pim_rpf *rp = RP(pim_ifp->pim, sg->grp); + pim_addr rpf_addr; if (!rp) { zlog_warn("%s: Lookup of RP failed for %pSG", __func__, @@ -94,13 +89,11 @@ static void recv_join(struct interface *ifp, struct pim_neighbor *neigh, * If the RP sent in the message is not * our RP for the group, drop the message */ - if (sg->src.s_addr != rp->rpf_addr.u.prefix4.s_addr) { - char local_rp[INET_ADDRSTRLEN]; - pim_inet4_dump("<local?>", rp->rpf_addr.u.prefix4, - local_rp, sizeof(local_rp)); + rpf_addr = pim_addr_from_prefix(&rp->rpf_addr); + if (pim_addr_cmp(sg->src, rpf_addr)) { zlog_warn( - "%s: Specified RP(%pPAs) in join is different than our configured RP(%s)", - __func__, &sg->src, local_rp); + "%s: Specified RP(%pPAs) in join is different than our configured RP(%pPAs)", + __func__, &sg->src, &rpf_addr); return; } @@ -120,24 +113,17 @@ static void recv_join(struct interface *ifp, struct pim_neighbor *neigh, } static void recv_prune(struct interface *ifp, struct pim_neighbor *neigh, - uint16_t holdtime, struct in_addr upstream, - pim_sgaddr *sg, uint8_t source_flags) + uint16_t holdtime, pim_addr upstream, pim_sgaddr *sg, + uint8_t source_flags) { struct pim_interface *pim_ifp = NULL; - if (PIM_DEBUG_PIM_TRACE) { - char up_str[INET_ADDRSTRLEN]; - char neigh_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str)); - pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, - sizeof(neigh_str)); - zlog_debug("%s: prune (S,G)=%pSG rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s", - __func__, sg, - source_flags & PIM_RPT_BIT_MASK, - source_flags & PIM_WILDCARD_BIT_MASK, up_str, - holdtime, - neigh_str, ifp->name); - } + if (PIM_DEBUG_PIM_TRACE) + zlog_debug( + "%s: prune (S,G)=%pSG rpt=%d wc=%d upstream=%pPAs holdtime=%d from %pPA on %s", + __func__, sg, source_flags & PIM_RPT_BIT_MASK, + source_flags & PIM_WILDCARD_BIT_MASK, &upstream, + holdtime, &neigh->source_addr, ifp->name); pim_ifp = ifp->info; assert(pim_ifp); @@ -165,7 +151,8 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, struct in_addr src_addr, uint8_t *tlv_buf, int tlv_buf_size) { - struct prefix msg_upstream_addr; + pim_addr msg_upstream_addr; + bool wrong_af = false; struct pim_interface *pim_ifp; uint8_t msg_num_groups; uint16_t msg_holdtime; @@ -184,8 +171,8 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, /* Parse ucast addr */ - addr_offset = - pim_parse_addr_ucast(&msg_upstream_addr, buf, pastend - buf); + addr_offset = pim_parse_addr_ucast(&msg_upstream_addr, buf, + pastend - buf, &wrong_af); if (addr_offset < 1) { char src_str[INET_ADDRSTRLEN]; pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); @@ -198,12 +185,12 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, /* Check upstream address family */ - if (msg_upstream_addr.family != AF_INET) { + if (wrong_af) { char src_str[INET_ADDRSTRLEN]; pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); zlog_warn( - "%s: ignoring join/prune directed to unexpected addr family=%d from %s on %s", - __func__, msg_upstream_addr.family, src_str, ifp->name); + "%s: ignoring join/prune directed to unexpected addr family from %s on %s", + __func__, src_str, ifp->name); return -2; } @@ -226,14 +213,11 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, if (PIM_DEBUG_PIM_J_P) { char src_str[INET_ADDRSTRLEN]; - char upstream_str[INET_ADDRSTRLEN]; pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); - pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4, - upstream_str, sizeof(upstream_str)); zlog_debug( - "%s: join/prune upstream=%s groups=%d holdtime=%d from %s on %s", - __func__, upstream_str, msg_num_groups, msg_holdtime, - src_str, ifp->name); + "%s: join/prune upstream=%pPAs groups=%d holdtime=%d from %s on %s", + __func__, &msg_upstream_addr, msg_num_groups, + msg_holdtime, src_str, ifp->name); } /* Scan groups */ @@ -271,14 +255,11 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, if (PIM_DEBUG_PIM_J_P) { char src_str[INET_ADDRSTRLEN]; - char upstream_str[INET_ADDRSTRLEN]; pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); - pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4, - upstream_str, sizeof(upstream_str)); zlog_debug( - "%s: join/prune upstream=%s group=%pPA/32 join_src=%d prune_src=%d from %s on %s", - __func__, upstream_str, &sg.grp, + "%s: join/prune upstream=%pPAs group=%pPA/32 join_src=%d prune_src=%d from %s on %s", + __func__, &msg_upstream_addr, &sg.grp, msg_num_joined_sources, msg_num_pruned_sources, src_str, ifp->name); } @@ -300,9 +281,8 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, if (filtered) continue; - recv_join(ifp, neigh, msg_holdtime, - msg_upstream_addr.u.prefix4, &sg, - msg_source_flags); + recv_join(ifp, neigh, msg_holdtime, msg_upstream_addr, + &sg, msg_source_flags); if (pim_addr_is_any(sg.src)) { starg_ch = pim_ifchannel_find(ifp, &sg); @@ -326,9 +306,8 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, if (filtered) continue; - recv_prune(ifp, neigh, msg_holdtime, - msg_upstream_addr.u.prefix4, &sg, - msg_source_flags); + recv_prune(ifp, neigh, msg_holdtime, msg_upstream_addr, + &sg, msg_source_flags); /* * So if we are receiving a S,G,RPT prune * before we have any data for that S,G @@ -516,7 +495,7 @@ int pim_joinprune_send(struct pim_rpf *rpf, struct list *groups) grp = &msg->groups[0]; curr_ptr = (uint8_t *)grp; packet_size = sizeof(struct pim_msg_header); - packet_size += sizeof(struct pim_encoded_ipv4_unicast); + packet_size += sizeof(pim_encoded_unicast); packet_size += 4; // reserved (1) + groups (1) + holdtime (2) @@ -525,14 +504,11 @@ int pim_joinprune_send(struct pim_rpf *rpf, struct list *groups) } if (PIM_DEBUG_PIM_J_P) { char dst_str[INET_ADDRSTRLEN]; - char grp_str[INET_ADDRSTRLEN]; pim_inet4_dump("<dst?>", rpf->rpf_addr.u.prefix4, dst_str, sizeof(dst_str)); - pim_inet4_dump("<grp?>", group->group, grp_str, - sizeof(grp_str)); zlog_debug( - "%s: sending (G)=%s to upstream=%s on interface %s", - __func__, grp_str, dst_str, + "%s: sending (G)=%pPAs to upstream=%s on interface %s", + __func__, &group->group, dst_str, rpf->source_nexthop.interface->name); } @@ -564,7 +540,7 @@ int pim_joinprune_send(struct pim_rpf *rpf, struct list *groups) grp = &msg->groups[0]; curr_ptr = (uint8_t *)grp; packet_size = sizeof(struct pim_msg_header); - packet_size += sizeof(struct pim_encoded_ipv4_unicast); + packet_size += sizeof(pim_encoded_unicast); packet_size += 4; // reserved (1) + groups (1) + holdtime (2) diff --git a/pimd/pim_jp_agg.c b/pimd/pim_jp_agg.c index feeef15f81..42ad5dcd1e 100644 --- a/pimd/pim_jp_agg.c +++ b/pimd/pim_jp_agg.c @@ -60,13 +60,7 @@ int pim_jp_agg_group_list_cmp(void *arg1, void *arg2) const struct pim_jp_agg_group *jag2 = (const struct pim_jp_agg_group *)arg2; - if (jag1->group.s_addr < jag2->group.s_addr) - return -1; - - if (jag1->group.s_addr > jag2->group.s_addr) - return 1; - - return 0; + return pim_addr_cmp(jag1->group, jag2->group); } static int pim_jp_agg_src_cmp(void *arg1, void *arg2) @@ -163,17 +157,10 @@ void pim_jp_agg_remove_group(struct list *group, struct pim_upstream *up, } if (nbr) { - if (PIM_DEBUG_TRACE) { - char src_str[INET_ADDRSTRLEN]; - - pim_inet4_dump("<src?>", nbr->source_addr, src_str, - sizeof(src_str)); - zlog_debug( - "up %s remove from nbr %s/%s jp-agg-list", - up->sg_str, - nbr->interface->name, - src_str); - } + if (PIM_DEBUG_TRACE) + zlog_debug("up %s remove from nbr %s/%pPAs jp-agg-list", + up->sg_str, nbr->interface->name, + &nbr->source_addr); } if (js) { @@ -290,17 +277,11 @@ void pim_jp_agg_add_group(struct list *group, struct pim_upstream *up, } if (nbr) { - if (PIM_DEBUG_TRACE) { - char src_str[INET_ADDRSTRLEN]; - - pim_inet4_dump("<src?>", nbr->source_addr, src_str, - sizeof(src_str)); - zlog_debug( - "up %s add to nbr %s/%s jp-agg-list", - up->sg_str, - up->rpf.source_nexthop.interface->name, - src_str); - } + if (PIM_DEBUG_TRACE) + zlog_debug("up %s add to nbr %s/%pPAs jp-agg-list", + up->sg_str, + up->rpf.source_nexthop.interface->name, + &nbr->source_addr); } if (!js) { diff --git a/pimd/pim_macro.c b/pimd/pim_macro.c index aa41033cea..0896c52a75 100644 --- a/pimd/pim_macro.c +++ b/pimd/pim_macro.c @@ -132,7 +132,7 @@ int pim_macro_ch_lost_assert(const struct pim_ifchannel *ch) return 0; /* false */ /* AssertWinner(S,G,I) == me ? */ - if (ch->ifassert_winner.s_addr == pim_ifp->primary_address.s_addr) + if (!pim_addr_cmp(ch->ifassert_winner, pim_ifp->primary_address)) return 0; /* false */ spt_assert_metric = pim_macro_spt_assert_metric( @@ -170,7 +170,7 @@ int pim_macro_chisin_pim_include(const struct pim_ifchannel *ch) return 0; /* false */ /* OR AssertWinner(S,G,I) == me ? */ - if (ch->ifassert_winner.s_addr == pim_ifp->primary_address.s_addr) + if (!pim_addr_cmp(ch->ifassert_winner, pim_ifp->primary_address)) return 1; /* true */ /* @@ -412,8 +412,8 @@ int pim_macro_assert_tracking_desired_eval(const struct pim_ifchannel *ch) return 1; /* true */ /* AssertWinner(S,G,I) == me ? */ - if (ch->ifassert_winner.s_addr - == pim_ifp->primary_address.s_addr) + if (!pim_addr_cmp(ch->ifassert_winner, + pim_ifp->primary_address)) return 1; /* true */ } diff --git a/pimd/pim_msg.c b/pimd/pim_msg.c index c493ded0c6..e25cf11549 100644 --- a/pimd/pim_msg.c +++ b/pimd/pim_msg.c @@ -97,6 +97,68 @@ uint8_t *pim_msg_addr_encode_ipv4_source(uint8_t *buf, struct in_addr addr, return buf + PIM_ENCODED_IPV4_SOURCE_SIZE; } +uint8_t *pim_msg_addr_encode_ipv6_source(uint8_t *buf, struct in6_addr addr, + uint8_t bits) +{ + buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV6; /* addr family */ + buf[1] = '\0'; /* native encoding */ + buf[2] = bits; + buf[3] = 128; /* mask len */ + buf += 4; + + memcpy(buf, &addr, sizeof(addr)); + buf += sizeof(addr); + + return buf; +} + +uint8_t *pim_msg_addr_encode_ipv6_ucast(uint8_t *buf, struct in6_addr addr) +{ + buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV6; /* addr family */ + buf[1] = '\0'; /* native encoding */ + buf += 2; + + memcpy(buf, &addr, sizeof(addr)); + buf += sizeof(addr); + + return buf; +} + +uint8_t *pim_msg_addr_encode_ipv6_group(uint8_t *buf, struct in6_addr addr) +{ + buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV6; /* addr family */ + buf[1] = '\0'; /* native encoding */ + buf[2] = '\0'; /* reserved */ + buf[3] = 128; /* mask len */ + buf += 4; + + memcpy(buf, &addr, sizeof(addr)); + buf += sizeof(addr); + + return buf; +} + +#if PIM_IPV == 4 || !defined(PIM_V6_TEMP_BREAK) +#define pim_msg_addr_encode(what) pim_msg_addr_encode_ipv4_##what +#else +#define pim_msg_addr_encode(what) pim_msg_addr_encode_ipv6_##what +#endif + +uint8_t *pim_msg_addr_encode_ucast(uint8_t *buf, pim_addr addr) +{ + return pim_msg_addr_encode(ucast)(buf, addr); +} + +uint8_t *pim_msg_addr_encode_group(uint8_t *buf, pim_addr addr) +{ + return pim_msg_addr_encode(group)(buf, addr); +} + +uint8_t *pim_msg_addr_encode_source(uint8_t *buf, pim_addr addr, uint8_t bits) +{ + return pim_msg_addr_encode(source)(buf, addr, bits); +} + /* * For the given 'struct pim_jp_sources' list * determine the size_t it would take up. @@ -109,10 +171,10 @@ size_t pim_msg_get_jp_group_size(struct list *sources) if (!sources) return 0; - size += sizeof(struct pim_encoded_group_ipv4); + size += sizeof(pim_encoded_group); size += 4; // Joined sources (2) + Pruned Sources (2) - size += sizeof(struct pim_encoded_source_ipv4) * sources->count; + size += sizeof(pim_encoded_source) * sources->count; js = listgetdata(listhead(sources)); if (js && pim_addr_is_any(js->up->sg.src) && js->is_join) { @@ -137,8 +199,7 @@ size_t pim_msg_get_jp_group_size(struct list *sources) if (child->rpf.source_nexthop.interface && !pim_rpf_is_same(&up->rpf, &child->rpf)) { - size += sizeof( - struct pim_encoded_source_ipv4); + size += sizeof(pim_encoded_source); PIM_UPSTREAM_FLAG_SET_SEND_SG_RPT_PRUNE( child->flags); if (PIM_DEBUG_PIM_PACKETS) @@ -156,8 +217,7 @@ size_t pim_msg_get_jp_group_size(struct list *sources) * but it's inherited OIL is empty. So just * prune it off. */ - size += sizeof( - struct pim_encoded_source_ipv4); + size += sizeof(pim_encoded_source); PIM_UPSTREAM_FLAG_SET_SEND_SG_RPT_PRUNE( child->flags); if (PIM_DEBUG_PIM_PACKETS) @@ -179,12 +239,12 @@ size_t pim_msg_build_jp_groups(struct pim_jp_groups *grp, struct listnode *node, *nnode; struct pim_jp_sources *source; struct pim_upstream *up = NULL; - struct in_addr stosend; + pim_addr stosend; uint8_t bits; uint8_t tgroups = 0; memset(grp, 0, size); - pim_msg_addr_encode_ipv4_group((uint8_t *)&grp->g, sgs->group); + pim_msg_addr_encode_group((uint8_t *)&grp->g, sgs->group); for (ALL_LIST_ELEMENTS(sgs->sources, node, nnode, source)) { /* number of joined/pruned sources */ @@ -198,7 +258,7 @@ size_t pim_msg_build_jp_groups(struct pim_jp_groups *grp, struct pim_rpf *rpf = pim_rp_g(pim, source->up->sg.grp); bits = PIM_ENCODE_SPARSE_BIT | PIM_ENCODE_WC_BIT | PIM_ENCODE_RPT_BIT; - stosend = rpf->rpf_addr.u.prefix4; + stosend = pim_addr_from_prefix(&rpf->rpf_addr); /* Only Send SGRpt in case of *,G Join */ if (source->is_join) up = source->up; @@ -207,8 +267,8 @@ size_t pim_msg_build_jp_groups(struct pim_jp_groups *grp, stosend = source->up->sg.src; } - pim_msg_addr_encode_ipv4_source((uint8_t *)&grp->s[tgroups], - stosend, bits); + pim_msg_addr_encode_source((uint8_t *)&grp->s[tgroups], stosend, + bits); tgroups++; } @@ -218,11 +278,11 @@ size_t pim_msg_build_jp_groups(struct pim_jp_groups *grp, for (ALL_LIST_ELEMENTS(up->sources, node, nnode, child)) { if (PIM_UPSTREAM_FLAG_TEST_SEND_SG_RPT_PRUNE( child->flags)) { - pim_msg_addr_encode_ipv4_source( + pim_msg_addr_encode_source( (uint8_t *)&grp->s[tgroups], child->sg.src, - PIM_ENCODE_SPARSE_BIT - | PIM_ENCODE_RPT_BIT); + PIM_ENCODE_SPARSE_BIT | + PIM_ENCODE_RPT_BIT); tgroups++; PIM_UPSTREAM_FLAG_UNSET_SEND_SG_RPT_PRUNE( child->flags); diff --git a/pimd/pim_msg.h b/pimd/pim_msg.h index 2d69a4b03a..522e94504a 100644 --- a/pimd/pim_msg.h +++ b/pimd/pim_msg.h @@ -75,6 +75,12 @@ struct pim_encoded_ipv4_unicast { struct in_addr addr; } __attribute__((packed)); +struct pim_encoded_ipv6_unicast { + uint8_t family; + uint8_t reserved; + struct in6_addr addr; +} __attribute__((packed)); + /* * Encoded Group format. RFC 4601 Sec 4.9.1 * 0 1 2 3 @@ -103,6 +109,23 @@ struct pim_encoded_group_ipv4 { struct in_addr addr; } __attribute__((packed)); +struct pim_encoded_group_ipv6 { + uint8_t family; + uint8_t ne; +#if (BYTE_ORDER == LITTLE_ENDIAN) + uint8_t sz : 1; /* scope zone bit */ + uint8_t reserved : 6; /* Reserved */ + uint8_t bidir : 1; /* Bidir bit */ +#elif (BYTE_ORDER == BIG_ENDIAN) + uint8_t bidir : 1; /* Bidir bit */ + uint8_t reserved : 6; /* Reserved */ + uint8_t sz : 1; /* scope zone bit */ +#else +#error "Please set byte order" +#endif + uint8_t mask; + struct in6_addr addr; +} __attribute__((packed)); /* * Encoded Source format. RFC 4601 Sec 4.9.1 @@ -122,16 +145,36 @@ struct pim_encoded_source_ipv4 { struct in_addr addr; } __attribute__((packed)); +struct pim_encoded_source_ipv6 { + uint8_t family; + uint8_t ne; + uint8_t bits; + uint8_t mask; + struct in6_addr addr; +} __attribute__((packed)); + +/* clang-format off */ +#if PIM_IPV == 4 +typedef struct pim_encoded_ipv4_unicast pim_encoded_unicast; +typedef struct pim_encoded_group_ipv4 pim_encoded_group; +typedef struct pim_encoded_source_ipv4 pim_encoded_source; +#else +typedef struct pim_encoded_ipv6_unicast pim_encoded_unicast; +typedef struct pim_encoded_group_ipv6 pim_encoded_group; +typedef struct pim_encoded_source_ipv6 pim_encoded_source; +#endif +/* clang-format on */ + struct pim_jp_groups { - struct pim_encoded_group_ipv4 g; + pim_encoded_group g; uint16_t joins; uint16_t prunes; - struct pim_encoded_source_ipv4 s[1]; + pim_encoded_source s[1]; } __attribute__((packed)); struct pim_jp { struct pim_msg_header header; - struct pim_encoded_ipv4_unicast addr; + pim_encoded_unicast addr; uint8_t reserved; uint8_t num_groups; uint16_t holdtime; @@ -149,6 +192,14 @@ uint8_t *pim_msg_addr_encode_ipv4_group(uint8_t *buf, struct in_addr addr); uint8_t *pim_msg_addr_encode_ipv4_source(uint8_t *buf, struct in_addr addr, uint8_t bits); +uint8_t *pim_msg_addr_encode_ipv6_ucast(uint8_t *buf, struct in6_addr addr); +uint8_t *pim_msg_addr_encode_ipv6_group(uint8_t *buf, struct in6_addr addr); +uint8_t *pim_msg_addr_encode_ipv6_source(uint8_t *buf, struct in6_addr addr, + uint8_t bits); + +uint8_t *pim_msg_addr_encode_ucast(uint8_t *buf, pim_addr addr); +uint8_t *pim_msg_addr_encode_group(uint8_t *buf, pim_addr addr); +uint8_t *pim_msg_addr_encode_source(uint8_t *buf, pim_addr addr, uint8_t bits); size_t pim_msg_get_jp_group_size(struct list *sources); size_t pim_msg_build_jp_groups(struct pim_jp_groups *grp, diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c index 530c2e429b..6e3d2739e7 100644 --- a/pimd/pim_neighbor.c +++ b/pimd/pim_neighbor.c @@ -58,10 +58,8 @@ static void dr_election_by_addr(struct interface *ifp) } for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) { - if (ntohl(neigh->source_addr.s_addr) - > ntohl(pim_ifp->pim_dr_addr.s_addr)) { + if (pim_addr_cmp(neigh->source_addr, pim_ifp->pim_dr_addr) > 0) pim_ifp->pim_dr_addr = neigh->source_addr; - } } } @@ -85,15 +83,14 @@ static void dr_election_by_pri(struct interface *ifp) for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) { if (PIM_DEBUG_PIM_TRACE) { - zlog_info("%s: neigh pri %u addr %x if dr addr %x", + zlog_info("%s: neigh pri %u addr %pPA if dr addr %pPA", __func__, neigh->dr_priority, - ntohl(neigh->source_addr.s_addr), - ntohl(pim_ifp->pim_dr_addr.s_addr)); + &neigh->source_addr, &pim_ifp->pim_dr_addr); } - if ((neigh->dr_priority > dr_pri) - || ((neigh->dr_priority == dr_pri) - && (ntohl(neigh->source_addr.s_addr) - > ntohl(pim_ifp->pim_dr_addr.s_addr)))) { + if ((neigh->dr_priority > dr_pri) || + ((neigh->dr_priority == dr_pri) && + (pim_addr_cmp(neigh->source_addr, pim_ifp->pim_dr_addr) > + 0))) { pim_ifp->pim_dr_addr = neigh->source_addr; dr_pri = neigh->dr_priority; } @@ -110,7 +107,7 @@ static void dr_election_by_pri(struct interface *ifp) int pim_if_dr_election(struct interface *ifp) { struct pim_interface *pim_ifp = ifp->info; - struct in_addr old_dr_addr; + pim_addr old_dr_addr; ++pim_ifp->pim_dr_election_count; @@ -123,18 +120,13 @@ int pim_if_dr_election(struct interface *ifp) } /* DR changed ? */ - if (old_dr_addr.s_addr != pim_ifp->pim_dr_addr.s_addr) { - - if (PIM_DEBUG_PIM_EVENTS) { - char dr_old_str[INET_ADDRSTRLEN]; - char dr_new_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<old_dr?>", old_dr_addr, dr_old_str, - sizeof(dr_old_str)); - pim_inet4_dump("<new_dr?>", pim_ifp->pim_dr_addr, - dr_new_str, sizeof(dr_new_str)); - zlog_debug("%s: DR was %s now is %s on interface %s", - __func__, dr_old_str, dr_new_str, ifp->name); - } + if (pim_addr_cmp(old_dr_addr, pim_ifp->pim_dr_addr)) { + + if (PIM_DEBUG_PIM_EVENTS) + zlog_debug( + "%s: DR was %pPA now is %pPA on interface %s", + __func__, &old_dr_addr, &pim_ifp->pim_dr_addr, + ifp->name); pim_ifp->pim_dr_election_last = pim_time_monotonic_sec(); /* timestamp */ @@ -218,14 +210,10 @@ static int on_neighbor_timer(struct thread *t) ifp = neigh->interface; - if (PIM_DEBUG_PIM_TRACE) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", neigh->source_addr, src_str, - sizeof(src_str)); + if (PIM_DEBUG_PIM_TRACE) zlog_debug( - "Expired %d sec holdtime for neighbor %s on interface %s", - neigh->holdtime, src_str, ifp->name); - } + "Expired %d sec holdtime for neighbor %pPA on interface %s", + neigh->holdtime, &neigh->source_addr, ifp->name); snprintf(msg, sizeof(msg), "%d-sec holdtime expired", neigh->holdtime); pim_neighbor_delete(ifp, neigh, msg); @@ -255,14 +243,10 @@ void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime) return; } - if (PIM_DEBUG_PIM_TRACE_DETAIL) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", neigh->source_addr, src_str, - sizeof(src_str)); - zlog_debug("%s: starting %u sec timer for neighbor %s on %s", - __func__, neigh->holdtime, src_str, + if (PIM_DEBUG_PIM_TRACE_DETAIL) + zlog_debug("%s: starting %u sec timer for neighbor %pPA on %s", + __func__, neigh->holdtime, &neigh->source_addr, neigh->interface->name); - } thread_add_timer(router->master, on_neighbor_timer, neigh, neigh->holdtime, &neigh->t_expire_timer); @@ -273,17 +257,14 @@ static int on_neighbor_jp_timer(struct thread *t) struct pim_neighbor *neigh = THREAD_ARG(t); struct pim_rpf rpf; - if (PIM_DEBUG_PIM_TRACE) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", neigh->source_addr, src_str, - sizeof(src_str)); - zlog_debug("%s:Sending JP Agg to %s on %s with %d groups", - __func__, src_str, neigh->interface->name, + if (PIM_DEBUG_PIM_TRACE) + zlog_debug("%s:Sending JP Agg to %pPA on %s with %d groups", + __func__, &neigh->source_addr, + neigh->interface->name, neigh->upstream_jp_agg->count); - } rpf.source_nexthop.interface = neigh->interface; - rpf.rpf_addr.u.prefix4 = neigh->source_addr; + pim_addr_to_prefix(&rpf.rpf_addr, neigh->source_addr); pim_joinprune_send(&rpf, neigh->upstream_jp_agg); thread_add_timer(router->master, on_neighbor_jp_timer, neigh, @@ -300,7 +281,7 @@ static void pim_neighbor_start_jp_timer(struct pim_neighbor *neigh) } static struct pim_neighbor * -pim_neighbor_new(struct interface *ifp, struct in_addr source_addr, +pim_neighbor_new(struct interface *ifp, pim_addr source_addr, pim_hello_options hello_options, uint16_t holdtime, uint16_t propagation_delay, uint16_t override_interval, uint32_t dr_priority, uint32_t generation_id, @@ -308,7 +289,6 @@ pim_neighbor_new(struct interface *ifp, struct in_addr source_addr, { struct pim_interface *pim_ifp; struct pim_neighbor *neigh; - char src_str[INET_ADDRSTRLEN]; assert(ifp); pim_ifp = ifp->info; @@ -343,15 +323,12 @@ pim_neighbor_new(struct interface *ifp, struct in_addr source_addr, */ PIM_IF_FLAG_UNSET_HELLO_SENT(pim_ifp->flags); - pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str)); - - if (PIM_DEBUG_PIM_EVENTS) { - zlog_debug("%s: creating PIM neighbor %s on interface %s", - __func__, src_str, ifp->name); - } + if (PIM_DEBUG_PIM_EVENTS) + zlog_debug("%s: creating PIM neighbor %pPA on interface %s", + __func__, &source_addr, ifp->name); - zlog_notice("PIM NEIGHBOR UP: neighbor %s on interface %s", src_str, - ifp->name); + zlog_notice("PIM NEIGHBOR UP: neighbor %pPA on interface %s", + &source_addr, ifp->name); if (neigh->propagation_delay_msec > pim_ifp->pim_neighbors_highest_propagation_delay_msec) { @@ -448,7 +425,7 @@ struct pim_neighbor *pim_neighbor_find_by_secondary(struct interface *ifp, } struct pim_neighbor *pim_neighbor_find(struct interface *ifp, - struct in_addr source_addr) + pim_addr source_addr) { struct pim_interface *pim_ifp; struct listnode *node; @@ -462,7 +439,7 @@ struct pim_neighbor *pim_neighbor_find(struct interface *ifp, return NULL; for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) { - if (source_addr.s_addr == neigh->source_addr.s_addr) { + if (!pim_addr_cmp(source_addr, neigh->source_addr)) { return neigh; } } @@ -470,6 +447,15 @@ struct pim_neighbor *pim_neighbor_find(struct interface *ifp, return NULL; } +struct pim_neighbor *pim_neighbor_find_prefix(struct interface *ifp, + const struct prefix *src_prefix) +{ + pim_addr addr; + + addr = pim_addr_from_prefix(src_prefix); + return pim_neighbor_find(ifp, addr); +} + /* * Find the *one* interface out * this interface. If more than @@ -486,7 +472,7 @@ struct pim_neighbor *pim_neighbor_find_if(struct interface *ifp) } struct pim_neighbor * -pim_neighbor_add(struct interface *ifp, struct in_addr source_addr, +pim_neighbor_add(struct interface *ifp, pim_addr source_addr, pim_hello_options hello_options, uint16_t holdtime, uint16_t propagation_delay, uint16_t override_interval, uint32_t dr_priority, uint32_t generation_id, @@ -507,11 +493,8 @@ pim_neighbor_add(struct interface *ifp, struct in_addr source_addr, listnode_add(pim_ifp->pim_neighbor_list, neigh); - if (PIM_DEBUG_PIM_TRACE_DETAIL) { - char str[INET_ADDRSTRLEN]; - pim_inet4_dump("<nht_nbr?>", source_addr, str, sizeof(str)); - zlog_debug("%s: neighbor %s added ", __func__, str); - } + if (PIM_DEBUG_PIM_TRACE_DETAIL) + zlog_debug("%s: neighbor %pPA added ", __func__, &source_addr); /* RFC 4601: 4.3.2. DR Election @@ -610,14 +593,12 @@ void pim_neighbor_delete(struct interface *ifp, struct pim_neighbor *neigh, const char *delete_message) { struct pim_interface *pim_ifp; - char src_str[INET_ADDRSTRLEN]; pim_ifp = ifp->info; assert(pim_ifp); - pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str)); - zlog_notice("PIM NEIGHBOR DOWN: neighbor %s on interface %s: %s", - src_str, ifp->name, delete_message); + zlog_notice("PIM NEIGHBOR DOWN: neighbor %pPA on interface %s: %s", + &neigh->source_addr, ifp->name, delete_message); THREAD_OFF(neigh->t_expire_timer); @@ -664,8 +645,8 @@ void pim_neighbor_delete(struct interface *ifp, struct pim_neighbor *neigh, } if (PIM_DEBUG_PIM_TRACE) { - zlog_debug("%s: deleting PIM neighbor %s on interface %s", - __func__, src_str, ifp->name); + zlog_debug("%s: deleting PIM neighbor %pPA on interface %s", + __func__, &neigh->source_addr, ifp->name); } listnode_delete(pim_ifp->pim_neighbor_list, neigh); @@ -720,8 +701,7 @@ struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh, administrator in a rate-limited manner. */ static void delete_from_neigh_addr(struct interface *ifp, - struct list *addr_list, - struct in_addr neigh_addr) + struct list *addr_list, pim_addr neigh_addr) { struct listnode *addr_node; struct prefix *addr; @@ -752,24 +732,15 @@ static void delete_from_neigh_addr(struct interface *ifp, neigh, addr); if (p) { char addr_str[INET_ADDRSTRLEN]; - char this_neigh_str[INET_ADDRSTRLEN]; - char other_neigh_str[INET_ADDRSTRLEN]; pim_inet4_dump( "<addr?>", addr->u.prefix4, addr_str, sizeof(addr_str)); - pim_inet4_dump("<neigh1?>", neigh_addr, - this_neigh_str, - sizeof(this_neigh_str)); - pim_inet4_dump("<neigh2?>", - neigh->source_addr, - other_neigh_str, - sizeof(other_neigh_str)); zlog_info( - "secondary addr %s recvd from neigh %s deleted from neigh %s on %s", - addr_str, this_neigh_str, - other_neigh_str, ifp->name); + "secondary addr %s recvd from neigh %pPA deleted from neigh %pPA on %s", + addr_str, &neigh_addr, + &neigh->source_addr, ifp->name); listnode_delete(neigh->prefix_list, p); prefix_free(&p); diff --git a/pimd/pim_neighbor.h b/pimd/pim_neighbor.h index 12c469ae2a..2673d22480 100644 --- a/pimd/pim_neighbor.h +++ b/pimd/pim_neighbor.h @@ -51,7 +51,9 @@ struct pim_neighbor { void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime); void pim_neighbor_free(struct pim_neighbor *neigh); struct pim_neighbor *pim_neighbor_find(struct interface *ifp, - struct in_addr source_addr); + pim_addr source_addr); +struct pim_neighbor *pim_neighbor_find_prefix(struct interface *ifp, + const struct prefix *src_prefix); struct pim_neighbor *pim_neighbor_find_by_secondary(struct interface *ifp, struct prefix *src); struct pim_neighbor *pim_neighbor_find_if(struct interface *ifp); @@ -60,7 +62,7 @@ struct pim_neighbor *pim_neighbor_find_if(struct interface *ifp); #define PIM_NEIGHBOR_SEND_DELAY 0 #define PIM_NEIGHBOR_SEND_NOW 1 struct pim_neighbor * -pim_neighbor_add(struct interface *ifp, struct in_addr source_addr, +pim_neighbor_add(struct interface *ifp, pim_addr source_addr, pim_hello_options hello_options, uint16_t holdtime, uint16_t propagation_delay, uint16_t override_interval, uint32_t dr_priority, uint32_t generation_id, diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c index 26ca48543f..beaa5c802b 100644 --- a/pimd/pim_nht.c +++ b/pimd/pim_nht.c @@ -237,10 +237,7 @@ void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr, if (!pim_addr_is_any(upstream->sg.src)) continue; - grp.family = AF_INET; - grp.prefixlen = IPV4_MAX_BITLEN; - grp.u.prefix4 = upstream->sg.grp; - + pim_addr_to_prefix(&grp, upstream->sg.grp); trp_info = pim_rp_find_match_group(pim, &grp); if (trp_info == rp) hash_release(pnc->upstream_hash, upstream); @@ -338,8 +335,7 @@ bool pim_nht_bsr_rpf_check(struct pim_instance *pim, struct in_addr bsr_addr, if (if_is_loopback(ifp) && if_is_loopback(src_ifp)) return true; - nbr = pim_neighbor_find(ifp, - znh->nexthop_addr.u.prefix4); + nbr = pim_neighbor_find_prefix(ifp, &znh->nexthop_addr); if (!nbr) continue; @@ -362,9 +358,10 @@ bool pim_nht_bsr_rpf_check(struct pim_instance *pim, struct in_addr bsr_addr, */ for (nh = pnc->nexthop; nh; nh = nh->next) { - struct in_addr nhaddr; + pim_addr nhaddr; switch (nh->type) { +#if PIM_IPV == 4 || !defined(PIM_V6_TEMP_BREAK) case NEXTHOP_TYPE_IPV4: if (nh->ifindex == IFINDEX_INTERNAL) continue; @@ -373,7 +370,16 @@ bool pim_nht_bsr_rpf_check(struct pim_instance *pim, struct in_addr bsr_addr, case NEXTHOP_TYPE_IPV4_IFINDEX: nhaddr = nh->gate.ipv4; break; +#else + case NEXTHOP_TYPE_IPV6: + if (nh->ifindex == IFINDEX_INTERNAL) + continue; + /* fallthru */ + case NEXTHOP_TYPE_IPV6_IFINDEX: + nhaddr = nh->gate.ipv6; + break; +#endif case NEXTHOP_TYPE_IFINDEX: nhaddr = bsr_addr; break; @@ -550,9 +556,9 @@ static int pim_ecmp_nexthop_search(struct pim_instance *pim, if (curr_route_valid && !pim_if_connected_to_source(nexthop->interface, src->u.prefix4)) { - nbr = pim_neighbor_find( + nbr = pim_neighbor_find_prefix( nexthop->interface, - nexthop->mrib_nexthop_addr.u.prefix4); + &nexthop->mrib_nexthop_addr); if (!nbr && !if_is_loopback(nexthop->interface)) { if (PIM_DEBUG_PIM_NHT) @@ -599,8 +605,12 @@ static int pim_ecmp_nexthop_search(struct pim_instance *pim, ifps[i] = if_lookup_by_index(nh_node->ifindex, pim->vrf->vrf_id); if (ifps[i]) { - nbrs[i] = pim_neighbor_find(ifps[i], - nh_node->gate.ipv4); +#if PIM_IPV == 4 || !defined(PIM_V6_TEMP_BREAK) + pim_addr nhaddr = nh_node->gate.ipv4; +#else + pim_addr nhaddr = nh_node->gate.ipv6; +#endif + nbrs[i] = pim_neighbor_find(ifps[i], nhaddr); if (nbrs[i] || pim_if_connected_to_source(ifps[i], src->u.prefix4)) @@ -789,7 +799,11 @@ int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS) nbr = pim_neighbor_find_if(ifp1); /* Overwrite with Nbr address as NH addr */ if (nbr) +#if PIM_IPV == 4 || !defined(PIM_V6_TEMP_BREAK) nexthop->gate.ipv4 = nbr->source_addr; +#else + nexthop->gate.ipv6 = nbr->source_addr; +#endif else { // Mark nexthop address to 0 until PIM // Nbr is resolved. @@ -950,8 +964,8 @@ int pim_ecmp_nexthop_lookup(struct pim_instance *pim, ifps[i] = if_lookup_by_index(nexthop_tab[i].ifindex, pim->vrf->vrf_id); if (ifps[i]) { - nbrs[i] = pim_neighbor_find( - ifps[i], nexthop_tab[i].nexthop_addr.u.prefix4); + nbrs[i] = pim_neighbor_find_prefix( + ifps[i], &nexthop_tab[i].nexthop_addr); if (nbrs[i] || pim_if_connected_to_source(ifps[i], src->u.prefix4)) diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index 2142d9010b..93ccfd78df 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -570,7 +570,7 @@ static int pim_msg_send_frame(int fd, char *buf, size_t len, return 0; } -int pim_msg_send(int fd, pim_addr src, struct in_addr dst, uint8_t *pim_msg, +int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg, int pim_msg_size, const char *ifname) { struct sockaddr_in to; diff --git a/pimd/pim_pim.h b/pimd/pim_pim.h index b9fdb14dc0..1931e8cee8 100644 --- a/pimd/pim_pim.h +++ b/pimd/pim_pim.h @@ -56,8 +56,8 @@ void pim_hello_restart_triggered(struct interface *ifp); int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len); -int pim_msg_send(int fd, struct in_addr src, struct in_addr dst, - uint8_t *pim_msg, int pim_msg_size, const char *ifname); +int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg, + int pim_msg_size, const char *ifname); int pim_hello_send(struct interface *ifp, uint16_t holdtime); #endif /* PIM_PIM_H */ diff --git a/pimd/pim_register.c b/pimd/pim_register.c index 855d912566..2cc80f957c 100644 --- a/pimd/pim_register.c +++ b/pimd/pim_register.c @@ -72,7 +72,6 @@ void pim_register_stop_send(struct interface *ifp, pim_sgaddr *sg, unsigned int b1length = 0; unsigned int length; uint8_t *b1; - struct prefix p; if (PIM_DEBUG_PIM_REG) { zlog_debug("Sending Register stop for %pSG to %pI4 on %s", sg, @@ -86,10 +85,7 @@ void pim_register_stop_send(struct interface *ifp, pim_sgaddr *sg, b1length += length; b1 += length; - p.family = AF_INET; - p.u.prefix4 = sg->src; - p.prefixlen = IPV4_MAX_BITLEN; - length = pim_encode_addr_ucast(b1, &p); + length = pim_encode_addr_ucast(b1, sg->src); b1length += length; pim_msg_build_header(buffer, b1length + PIM_MSG_REGISTER_STOP_LEN, @@ -117,8 +113,8 @@ int pim_register_stop_recv(struct interface *ifp, uint8_t *buf, int buf_size) struct pim_interface *pim_ifp = ifp->info; struct pim_instance *pim = pim_ifp->pim; struct pim_upstream *upstream = NULL; - struct prefix source; pim_sgaddr sg; + bool wrong_af = false; int l; ++pim_ifp->pim_ifstat_reg_stop_recv; @@ -127,8 +123,12 @@ int pim_register_stop_recv(struct interface *ifp, uint8_t *buf, int buf_size) l = pim_parse_addr_group(&sg, buf, buf_size); buf += l; buf_size -= l; - pim_parse_addr_ucast(&source, buf, buf_size); - sg.src = source.u.prefix4; + pim_parse_addr_ucast(&sg.src, buf, buf_size, &wrong_af); + + if (wrong_af) { + zlog_err("invalid AF in Register-Stop on %s", ifp->name); + return 0; + } upstream = pim_upstream_find(pim, &sg); if (!upstream) { @@ -399,11 +399,10 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr, struct prefix_list *plist; struct prefix src; - plist = prefix_list_lookup(AFI_IP, pim->register_plist); + plist = prefix_list_lookup(PIM_AFI, + pim->register_plist); - src.family = AF_INET; - src.prefixlen = IPV4_MAX_BITLEN; - src.u.prefix4 = sg.src; + pim_addr_to_prefix(&src, sg.src); if (prefix_list_apply(plist, &src) == PREFIX_DENY) { pim_register_stop_send(ifp, &sg, dest_addr, diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index f35adb0cea..a5183c9e9b 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -322,9 +322,11 @@ static int pim_rp_check_interface_addrs(struct rp_info *rp_info, { struct listnode *node; struct pim_secondary_addr *sec_addr; + pim_addr rpf_addr; - if (pim_ifp->primary_address.s_addr - == rp_info->rp.rpf_addr.u.prefix4.s_addr) + rpf_addr = pim_addr_from_prefix(&rp_info->rp.rpf_addr); + + if (!pim_addr_cmp(pim_ifp->primary_address, rpf_addr)) return 1; if (!pim_ifp->sec_addr_list) { @@ -362,8 +364,8 @@ void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up) { struct pim_rpf old_rpf; enum pim_rpf_result rpf_result; - struct in_addr old_upstream_addr; - struct in_addr new_upstream_addr; + pim_addr old_upstream_addr; + pim_addr new_upstream_addr; struct prefix nht_p; old_upstream_addr = up->upstream_addr; @@ -374,7 +376,7 @@ void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up) zlog_debug("%s: pim upstream update for old upstream %pI4", __func__, &old_upstream_addr); - if (old_upstream_addr.s_addr == new_upstream_addr.s_addr) + if (!pim_addr_cmp(old_upstream_addr, new_upstream_addr)) return; /* Lets consider a case, where a PIM upstream has a better RP as a @@ -382,11 +384,9 @@ void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up) * This upstream has to be added to the upstream hash of new RP's * NHT(pnc) and has to be removed from old RP's NHT upstream hash */ - if (old_upstream_addr.s_addr != INADDR_ANY) { + if (!pim_addr_is_any(old_upstream_addr)) { /* Deregister addr with Zebra NHT */ - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4 = old_upstream_addr; + pim_addr_to_prefix(&nht_p, old_upstream_addr); if (PIM_DEBUG_PIM_TRACE) zlog_debug( "%s: Deregister upstream %s addr %pFX with Zebra NHT", @@ -536,14 +536,12 @@ int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, /* Find (*, G) upstream whose RP is not * configured yet */ - if ((up->upstream_addr.s_addr == INADDR_ANY) && + if (pim_addr_is_any(up->upstream_addr) && pim_addr_is_any(up->sg.src)) { struct prefix grp; struct rp_info *trp_info; - grp.family = AF_INET; - grp.prefixlen = IPV4_MAX_BITLEN; - grp.u.prefix4 = up->sg.grp; + pim_addr_to_prefix(&grp, up->sg.grp); trp_info = pim_rp_find_match_group( pim, &grp); if (trp_info == rp_all) { @@ -632,9 +630,7 @@ int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, struct prefix grp; struct rp_info *trp_info; - grp.family = AF_INET; - grp.prefixlen = IPV4_MAX_BITLEN; - grp.u.prefix4 = up->sg.grp; + pim_addr_to_prefix(&grp, up->sg.grp); trp_info = pim_rp_find_match_group(pim, &grp); if (trp_info == rp_info) { @@ -778,17 +774,18 @@ int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr, /* Find the upstream (*, G) whose upstream address is * same as the deleted RP */ - if ((up->upstream_addr.s_addr == - rp_info->rp.rpf_addr.u.prefix4.s_addr) && + pim_addr rpf_addr; + + rpf_addr = pim_addr_from_prefix(&rp_info->rp.rpf_addr); + if (!pim_addr_cmp(up->upstream_addr, rpf_addr) && pim_addr_is_any(up->sg.src)) { struct prefix grp; - grp.family = AF_INET; - grp.prefixlen = IPV4_MAX_BITLEN; - grp.u.prefix4 = up->sg.grp; + + pim_addr_to_prefix(&grp, up->sg.grp); trp_info = pim_rp_find_match_group(pim, &grp); if (trp_info == rp_all) { pim_upstream_rpf_clear(pim, up); - up->upstream_addr.s_addr = INADDR_ANY; + up->upstream_addr = PIMADDR_ANY; } } } @@ -826,15 +823,14 @@ int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr, /* Find the upstream (*, G) whose upstream address is same as * the deleted RP */ - if ((up->upstream_addr.s_addr == - rp_info->rp.rpf_addr.u.prefix4.s_addr) && + pim_addr rpf_addr; + + rpf_addr = pim_addr_from_prefix(&rp_info->rp.rpf_addr); + if (!pim_addr_cmp(up->upstream_addr, rpf_addr) && pim_addr_is_any(up->sg.src)) { struct prefix grp; - grp.family = AF_INET; - grp.prefixlen = IPV4_MAX_BITLEN; - grp.u.prefix4 = up->sg.grp; - + pim_addr_to_prefix(&grp, up->sg.grp); trp_info = pim_rp_find_match_group(pim, &grp); /* RP not found for the group grp */ @@ -918,9 +914,7 @@ int pim_rp_change(struct pim_instance *pim, struct in_addr new_rp_addr, struct prefix grp; struct rp_info *trp_info; - grp.family = AF_INET; - grp.prefixlen = IPV4_MAX_BITLEN; - grp.u.prefix4 = up->sg.grp; + pim_addr_to_prefix(&grp, up->sg.grp); trp_info = pim_rp_find_match_group(pim, &grp); if (trp_info == rp_info) { @@ -1064,13 +1058,14 @@ void pim_i_am_rp_re_evaluate(struct pim_instance *pim) } } +#if PIM_IPV == 4 /* * I_am_RP(G) is true if the group-to-RP mapping indicates that * this router is the RP for the group. * * Since we only have static RP, all groups are part of this RP */ -int pim_rp_i_am_rp(struct pim_instance *pim, struct in_addr group) +int pim_rp_i_am_rp(struct pim_instance *pim, pim_addr group) { struct prefix g; struct rp_info *rp_info; @@ -1084,7 +1079,6 @@ int pim_rp_i_am_rp(struct pim_instance *pim, struct in_addr group) if (rp_info) return rp_info->i_am_rp; - return 0; } @@ -1093,7 +1087,7 @@ int pim_rp_i_am_rp(struct pim_instance *pim, struct in_addr group) * * Return the RP that the Group belongs too. */ -struct pim_rpf *pim_rp_g(struct pim_instance *pim, struct in_addr group) +struct pim_rpf *pim_rp_g(struct pim_instance *pim, pim_addr group) { struct prefix g; struct rp_info *rp_info; @@ -1135,8 +1129,8 @@ struct pim_rpf *pim_rp_g(struct pim_instance *pim, struct in_addr group) * then set the upstream addr as INADDR_ANY and return failure. * */ -int pim_rp_set_upstream_addr(struct pim_instance *pim, struct in_addr *up, - struct in_addr source, struct in_addr group) +int pim_rp_set_upstream_addr(struct pim_instance *pim, pim_addr *up, + pim_addr source, pim_addr group) { struct rp_info *rp_info; struct prefix g; @@ -1162,6 +1156,25 @@ int pim_rp_set_upstream_addr(struct pim_instance *pim, struct in_addr *up, return 1; } +#else +CPP_NOTICE("functions stubbed out for IPv6"); + +int pim_rp_i_am_rp(struct pim_instance *pim, pim_addr group) +{ + return 0; +} + +struct pim_rpf *pim_rp_g(struct pim_instance *pim, pim_addr group) +{ + return NULL; +} + +int pim_rp_set_upstream_addr(struct pim_instance *pim, pim_addr *up, + pim_addr source, pim_addr group) +{ + return 0; +} +#endif int pim_rp_config_write(struct pim_instance *pim, struct vty *vty, const char *spaces) @@ -1353,17 +1366,19 @@ void pim_resolve_rp_nh(struct pim_instance *pim, struct pim_neighbor *nbr) if (nbr->interface != ifp1) continue; +#if PIM_IPV == 4 || !defined(PIM_V6_TEMP_BREAK) nh_node->gate.ipv4 = nbr->source_addr; +#else + nh_node->gate.ipv6 = nbr->source_addr; +#endif if (PIM_DEBUG_PIM_NHT_RP) { char str[PREFIX_STRLEN]; - char str1[INET_ADDRSTRLEN]; - pim_inet4_dump("<nht_nbr?>", nbr->source_addr, - str1, sizeof(str1)); pim_addr_dump("<nht_addr?>", &nht_p, str, sizeof(str)); zlog_debug( - "%s: addr %s new nexthop addr %s interface %s", - __func__, str, str1, ifp1->name); + "%s: addr %s new nexthop addr %pPAs interface %s", + __func__, str, &nbr->source_addr, + ifp1->name); } } } diff --git a/pimd/pim_rp.h b/pimd/pim_rp.h index 595025e5c9..c223402ddd 100644 --- a/pimd/pim_rp.h +++ b/pimd/pim_rp.h @@ -65,17 +65,17 @@ int pim_rp_config_write(struct pim_instance *pim, struct vty *vty, void pim_rp_setup(struct pim_instance *pim); -int pim_rp_i_am_rp(struct pim_instance *pim, struct in_addr group); +int pim_rp_i_am_rp(struct pim_instance *pim, pim_addr group); void pim_rp_check_on_if_add(struct pim_interface *pim_ifp); void pim_i_am_rp_re_evaluate(struct pim_instance *pim); bool pim_rp_check_is_my_ip_address(struct pim_instance *pim, struct in_addr dest_addr); -int pim_rp_set_upstream_addr(struct pim_instance *pim, struct in_addr *up, - struct in_addr source, struct in_addr group); +int pim_rp_set_upstream_addr(struct pim_instance *pim, pim_addr *up, + pim_addr source, pim_addr group); -struct pim_rpf *pim_rp_g(struct pim_instance *pim, struct in_addr group); +struct pim_rpf *pim_rp_g(struct pim_instance *pim, pim_addr group); #define I_am_RP(P, G) pim_rp_i_am_rp ((P), (G)) #define RP(P, G) pim_rp_g ((P), (G)) diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c index 1e865a3956..2e8fc8e661 100644 --- a/pimd/pim_rpf.c +++ b/pimd/pim_rpf.c @@ -141,8 +141,8 @@ bool pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop, i++; } else if (neighbor_needed && !pim_if_connected_to_source(ifp, addr)) { - nbr = pim_neighbor_find( - ifp, nexthop_tab[i].nexthop_addr.u.prefix4); + nbr = pim_neighbor_find_prefix( + ifp, &nexthop_tab[i].nexthop_addr); if (PIM_DEBUG_PIM_TRACE_DETAIL) zlog_debug("ifp name: %s, pim nbr: %p", ifp->name, nbr); @@ -234,7 +234,7 @@ enum pim_rpf_result pim_rpf_update(struct pim_instance *pim, if (PIM_UPSTREAM_FLAG_TEST_STATIC_IIF(up->flags)) return PIM_RPF_OK; - if (up->upstream_addr.s_addr == INADDR_ANY) { + if (pim_addr_is_any(up->upstream_addr)) { zlog_debug("%s(%s): RP is not configured yet for %s", __func__, caller, up->sg_str); return PIM_RPF_OK; @@ -248,16 +248,10 @@ enum pim_rpf_result pim_rpf_update(struct pim_instance *pim, old->rpf_addr = saved.rpf_addr; } - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr; + pim_addr_to_prefix(&nht_p, up->upstream_addr); - src.family = AF_INET; - src.prefixlen = IPV4_MAX_BITLEN; - src.u.prefix4 = up->upstream_addr; // RP or Src address - grp.family = AF_INET; - grp.prefixlen = IPV4_MAX_BITLEN; - grp.u.prefix4 = up->sg.grp; + pim_addr_to_prefix(&src, up->upstream_addr); // RP or Src address + pim_addr_to_prefix(&grp, up->sg.grp); if ((pim_addr_is_any(up->sg.src) && I_am_RP(pim, up->sg.grp)) || PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)) @@ -398,9 +392,11 @@ static struct in_addr pim_rpf_find_rpf_addr(struct pim_upstream *up) /* return NBR( RPF_interface(S), MRIB.next_hop( S ) ) */ - neigh = pim_if_find_neighbor( - up->rpf.source_nexthop.interface, - up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4); + pim_addr nhaddr; + + nhaddr = + pim_addr_from_prefix(&up->rpf.source_nexthop.mrib_nexthop_addr); + neigh = pim_if_find_neighbor(up->rpf.source_nexthop.interface, nhaddr); if (neigh) rpf_addr = neigh->source_addr; else diff --git a/pimd/pim_ssm.c b/pimd/pim_ssm.c index 6c5883aebf..45aac7756a 100644 --- a/pimd/pim_ssm.c +++ b/pimd/pim_ssm.c @@ -83,23 +83,20 @@ static int pim_is_grp_standard_ssm(struct prefix *group) return prefix_match(&group_ssm, group); } -int pim_is_grp_ssm(struct pim_instance *pim, struct in_addr group_addr) +int pim_is_grp_ssm(struct pim_instance *pim, pim_addr group_addr) { struct pim_ssm *ssm; struct prefix group; struct prefix_list *plist; - memset(&group, 0, sizeof(group)); - group.family = AF_INET; - group.u.prefix4 = group_addr; - group.prefixlen = 32; + pim_addr_to_prefix(&group, group_addr); ssm = pim->ssm_info; if (!ssm->plist_name) { return pim_is_grp_standard_ssm(&group); } - plist = prefix_list_lookup(AFI_IP, ssm->plist_name); + plist = prefix_list_lookup(PIM_AFI, ssm->plist_name); if (!plist) return 0; diff --git a/pimd/pim_ssm.h b/pimd/pim_ssm.h index 7235ade8dc..117713b866 100644 --- a/pimd/pim_ssm.h +++ b/pimd/pim_ssm.h @@ -34,7 +34,7 @@ struct pim_ssm { void pim_ssm_prefix_list_update(struct pim_instance *pim, struct prefix_list *plist); -int pim_is_grp_ssm(struct pim_instance *pim, struct in_addr group_addr); +int pim_is_grp_ssm(struct pim_instance *pim, pim_addr group_addr); int pim_ssm_range_set(struct pim_instance *pim, vrf_id_t vrf_id, const char *plist_name); void *pim_ssm_init(void); diff --git a/pimd/pim_tlv.c b/pimd/pim_tlv.c index a4f60e5198..86403dd54a 100644 --- a/pimd/pim_tlv.c +++ b/pimd/pim_tlv.c @@ -29,6 +29,12 @@ #include "pim_str.h" #include "pim_msg.h" +#if PIM_IPV == 4 +#define PIM_MSG_ADDRESS_FAMILY PIM_MSG_ADDRESS_FAMILY_IPV4 +#else +#define PIM_MSG_ADDRESS_FAMILY PIM_MSG_ADDRESS_FAMILY_IPV6 +#endif + uint8_t *pim_tlv_append_uint16(uint8_t *buf, const uint8_t *buf_pastend, uint16_t option_type, uint16_t option_value) { @@ -117,7 +123,23 @@ uint8_t *pim_tlv_append_uint32(uint8_t *buf, const uint8_t *buf_pastend, * The unicast address as represented by the given Address Family * and Encoding Type. */ -int pim_encode_addr_ucast(uint8_t *buf, struct prefix *p) +int pim_encode_addr_ucast(uint8_t *buf, pim_addr addr) +{ + uint8_t *start = buf; + +#if PIM_IPV == 4 + *buf++ = PIM_MSG_ADDRESS_FAMILY_IPV4; +#else + *buf++ = PIM_MSG_ADDRESS_FAMILY_IPV6; +#endif + *buf++ = 0; + memcpy(buf, &addr, sizeof(addr)); + buf += sizeof(addr); + + return buf - start; +} + +int pim_encode_addr_ucast_prefix(uint8_t *buf, struct prefix *p) { switch (p->family) { case AF_INET: @@ -188,28 +210,22 @@ int pim_encode_addr_ucast(uint8_t *buf, struct prefix *p) * Contains the group address. */ int pim_encode_addr_group(uint8_t *buf, afi_t afi, int bidir, int scope, - struct in_addr group) + pim_addr group) { + uint8_t *start = buf; uint8_t flags = 0; flags |= bidir << 8; flags |= scope; - switch (afi) { - case AFI_IP: - *buf = PIM_MSG_ADDRESS_FAMILY_IPV4; - ++buf; - *buf = 0; - ++buf; - *buf = flags; - ++buf; - *buf = 32; - ++buf; - memcpy(buf, &group, sizeof(struct in_addr)); - return group_ipv4_encoding_len; - default: - return 0; - } + *buf++ = PIM_MSG_ADDRESS_FAMILY; + *buf++ = 0; + *buf++ = flags; + *buf++ = sizeof(group) / 8; + memcpy(buf, &group, sizeof(group)); + buf += sizeof(group); + + return buf - start; } uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, const uint8_t *buf_pastend, @@ -248,7 +264,7 @@ uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, const uint8_t *buf_pastend, if (p->family != family) continue; - l_encode = pim_encode_addr_ucast(curr, p); + l_encode = pim_encode_addr_ucast_prefix(curr, p); curr += l_encode; option_len += l_encode; } @@ -274,15 +290,13 @@ uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, const uint8_t *buf_pastend, } static int check_tlv_length(const char *label, const char *tlv_name, - const char *ifname, struct in_addr src_addr, + const char *ifname, pim_addr src_addr, int correct_len, int option_len) { if (option_len != correct_len) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); zlog_warn( - "%s: PIM hello %s TLV with incorrect value size=%d correct=%d from %s on interface %s", - label, tlv_name, option_len, correct_len, src_str, + "%s: PIM hello %s TLV with incorrect value size=%d correct=%d from %pPAs on interface %s", + label, tlv_name, option_len, correct_len, &src_addr, ifname); return -1; } @@ -290,49 +304,44 @@ static int check_tlv_length(const char *label, const char *tlv_name, return 0; } -static void check_tlv_redefinition_uint16( - const char *label, const char *tlv_name, const char *ifname, - struct in_addr src_addr, pim_hello_options options, - pim_hello_options opt_mask, uint16_t new, uint16_t old) +static void check_tlv_redefinition_uint16(const char *label, + const char *tlv_name, + const char *ifname, pim_addr src_addr, + pim_hello_options options, + pim_hello_options opt_mask, + uint16_t new, uint16_t old) { - if (PIM_OPTION_IS_SET(options, opt_mask)) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); + if (PIM_OPTION_IS_SET(options, opt_mask)) zlog_warn( - "%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s", - label, tlv_name, new, old, src_str, ifname); - } + "%s: PIM hello TLV redefined %s=%u old=%u from %pPAs on interface %s", + label, tlv_name, new, old, &src_addr, ifname); } -static void check_tlv_redefinition_uint32( - const char *label, const char *tlv_name, const char *ifname, - struct in_addr src_addr, pim_hello_options options, - pim_hello_options opt_mask, uint32_t new, uint32_t old) +static void check_tlv_redefinition_uint32(const char *label, + const char *tlv_name, + const char *ifname, pim_addr src_addr, + pim_hello_options options, + pim_hello_options opt_mask, + uint32_t new, uint32_t old) { - if (PIM_OPTION_IS_SET(options, opt_mask)) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); + if (PIM_OPTION_IS_SET(options, opt_mask)) zlog_warn( - "%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s", - label, tlv_name, new, old, src_str, ifname); - } + "%s: PIM hello TLV redefined %s=%u old=%u from %pPAs on interface %s", + label, tlv_name, new, old, &src_addr, ifname); } static void check_tlv_redefinition_uint32_hex( const char *label, const char *tlv_name, const char *ifname, - struct in_addr src_addr, pim_hello_options options, + pim_addr src_addr, pim_hello_options options, pim_hello_options opt_mask, uint32_t new, uint32_t old) { - if (PIM_OPTION_IS_SET(options, opt_mask)) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); + if (PIM_OPTION_IS_SET(options, opt_mask)) zlog_warn( - "%s: PIM hello TLV redefined %s=%08x old=%08x from %s on interface %s", - label, tlv_name, new, old, src_str, ifname); - } + "%s: PIM hello TLV redefined %s=%08x old=%08x from %pPAs on interface %s", + label, tlv_name, new, old, &src_addr, ifname); } -int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr, +int pim_tlv_parse_holdtime(const char *ifname, pim_addr src_addr, pim_hello_options *hello_options, uint16_t *hello_option_holdtime, uint16_t option_len, const uint8_t *tlv_curr) @@ -356,7 +365,7 @@ int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr, return 0; } -int pim_tlv_parse_lan_prune_delay(const char *ifname, struct in_addr src_addr, +int pim_tlv_parse_lan_prune_delay(const char *ifname, pim_addr src_addr, pim_hello_options *hello_options, uint16_t *hello_option_propagation_delay, uint16_t *hello_option_override_interval, @@ -392,7 +401,7 @@ int pim_tlv_parse_lan_prune_delay(const char *ifname, struct in_addr src_addr, return 0; } -int pim_tlv_parse_dr_priority(const char *ifname, struct in_addr src_addr, +int pim_tlv_parse_dr_priority(const char *ifname, pim_addr src_addr, pim_hello_options *hello_options, uint32_t *hello_option_dr_priority, uint16_t option_len, const uint8_t *tlv_curr) @@ -416,7 +425,7 @@ int pim_tlv_parse_dr_priority(const char *ifname, struct in_addr src_addr, return 0; } -int pim_tlv_parse_generation_id(const char *ifname, struct in_addr src_addr, +int pim_tlv_parse_generation_id(const char *ifname, pim_addr src_addr, pim_hello_options *hello_options, uint32_t *hello_option_generation_id, uint16_t option_len, const uint8_t *tlv_curr) @@ -441,7 +450,8 @@ int pim_tlv_parse_generation_id(const char *ifname, struct in_addr src_addr, return 0; } -int pim_parse_addr_ucast(struct prefix *p, const uint8_t *buf, int buf_size) +int pim_parse_addr_ucast_prefix(struct prefix *p, const uint8_t *buf, + int buf_size) { const int ucast_encoding_min_len = 3; /* 1 family + 1 type + 1 addr */ const uint8_t *addr; @@ -510,6 +520,25 @@ int pim_parse_addr_ucast(struct prefix *p, const uint8_t *buf, int buf_size) return addr - buf; } +int pim_parse_addr_ucast(pim_addr *out, const uint8_t *buf, int buf_size, + bool *wrong_af) +{ + struct prefix p; + int ret; + + ret = pim_parse_addr_ucast_prefix(&p, buf, buf_size); + if (ret < 0) + return ret; + + if (p.family != PIM_AF) { + *wrong_af = true; + return -5; + } + + memcpy(out, &p.u.val, sizeof(*out)); + return ret; +} + int pim_parse_addr_group(pim_sgaddr *sg, const uint8_t *buf, int buf_size) { const int grp_encoding_min_len = @@ -532,40 +561,32 @@ int pim_parse_addr_group(pim_sgaddr *sg, const uint8_t *buf, int buf_size) family = *addr++; type = *addr++; - //++addr; ++addr; /* skip b_reserved_z fields */ mask_len = *addr++; - switch (family) { - case PIM_MSG_ADDRESS_FAMILY_IPV4: - if (type) { - zlog_warn( - "%s: unknown group address encoding type=%d from", - __func__, type); - return -2; - } - - if ((addr + sizeof(struct in_addr)) > pastend) { - zlog_warn( - "%s: IPv4 group address overflow: left=%td needed=%zu from", - __func__, pastend - addr, - sizeof(struct in_addr)); - return -3; - } - - memcpy(&sg->grp.s_addr, addr, sizeof(struct in_addr)); - - addr += sizeof(struct in_addr); + if (type) { + zlog_warn("%s: unknown group address encoding type=%d from", + __func__, type); + return -2; + } - break; - default: { + if (family != PIM_MSG_ADDRESS_FAMILY) { zlog_warn( "%s: unknown group address encoding family=%d mask_len=%d from", __func__, family, mask_len); return -4; } + + if ((addr + sizeof(sg->grp)) > pastend) { + zlog_warn( + "%s: group address overflow: left=%td needed=%zu from", + __func__, pastend - addr, sizeof(sg->grp)); + return -3; } + memcpy(&sg->grp, addr, sizeof(sg->grp)); + addr += sizeof(sg->grp); + return addr - buf; } @@ -654,7 +675,7 @@ int pim_parse_addr_source(pim_sgaddr *sg, uint8_t *flags, const uint8_t *buf, } \ } -int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr, +int pim_tlv_parse_addr_list(const char *ifname, pim_addr src_addr, pim_hello_options *hello_options, struct list **hello_option_addr_list, uint16_t option_len, const uint8_t *tlv_curr) @@ -670,20 +691,18 @@ int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr, addr = tlv_curr; pastend = tlv_curr + option_len; while (addr < pastend) { - struct prefix tmp; + struct prefix tmp, src_pfx; int addr_offset; /* Parse ucast addr */ - addr_offset = pim_parse_addr_ucast(&tmp, addr, pastend - addr); + addr_offset = + pim_parse_addr_ucast_prefix(&tmp, addr, pastend - addr); if (addr_offset < 1) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, - sizeof(src_str)); zlog_warn( - "%s: pim_parse_addr_ucast() failure: from %s on %s", - __func__, src_str, ifname); + "%s: pim_parse_addr_ucast() failure: from %pPAs on %s", + __func__, &src_addr, ifname); FREE_ADDR_LIST(*hello_option_addr_list); return -1; } @@ -696,35 +715,28 @@ int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr, switch (tmp.family) { case AF_INET: { char addr_str[INET_ADDRSTRLEN]; - char src_str[INET_ADDRSTRLEN]; pim_inet4_dump("<addr?>", tmp.u.prefix4, addr_str, sizeof(addr_str)); - pim_inet4_dump("<src?>", src_addr, src_str, - sizeof(src_str)); zlog_debug( - "%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %s on %s", + "%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %pPAs on %s", __func__, *hello_option_addr_list ? ((int)listcount( - *hello_option_addr_list)) + *hello_option_addr_list)) : -1, - addr_str, src_str, ifname); + addr_str, &src_addr, ifname); } break; case AF_INET6: break; - default: { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, - sizeof(src_str)); + default: zlog_debug( - "%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %s on %s", + "%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %pPAs on %s", __func__, *hello_option_addr_list ? ((int)listcount( - *hello_option_addr_list)) + *hello_option_addr_list)) : -1, - src_str, ifname); - } + &src_addr, ifname); } } @@ -732,16 +744,12 @@ int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr, Exclude neighbor's primary address if incorrectly included in the secondary address list */ - if (tmp.family == AF_INET) { - if (tmp.u.prefix4.s_addr == src_addr.s_addr) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, - sizeof(src_str)); - zlog_warn( - "%s: ignoring primary address in secondary list from %s on %s", - __func__, src_str, ifname); - continue; - } + pim_addr_to_prefix(&src_pfx, src_addr); + if (!prefix_cmp(&tmp, &src_pfx)) { + zlog_warn( + "%s: ignoring primary address in secondary list from %pPAs on %s", + __func__, &src_addr, ifname); + continue; } /* diff --git a/pimd/pim_tlv.h b/pimd/pim_tlv.h index 1aa60d5dbb..64b3a0b6ba 100644 --- a/pimd/pim_tlv.h +++ b/pimd/pim_tlv.h @@ -84,33 +84,37 @@ uint8_t *pim_tlv_append_uint32(uint8_t *buf, const uint8_t *buf_pastend, uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, const uint8_t *buf_pastend, struct list *ifconnected, int family); -int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr, +int pim_tlv_parse_holdtime(const char *ifname, pim_addr src_addr, pim_hello_options *hello_options, uint16_t *hello_option_holdtime, uint16_t option_len, const uint8_t *tlv_curr); -int pim_tlv_parse_lan_prune_delay(const char *ifname, struct in_addr src_addr, +int pim_tlv_parse_lan_prune_delay(const char *ifname, pim_addr src_addr, pim_hello_options *hello_options, uint16_t *hello_option_propagation_delay, uint16_t *hello_option_override_interval, uint16_t option_len, const uint8_t *tlv_curr); -int pim_tlv_parse_dr_priority(const char *ifname, struct in_addr src_addr, +int pim_tlv_parse_dr_priority(const char *ifname, pim_addr src_addr, pim_hello_options *hello_options, uint32_t *hello_option_dr_priority, uint16_t option_len, const uint8_t *tlv_curr); -int pim_tlv_parse_generation_id(const char *ifname, struct in_addr src_addr, +int pim_tlv_parse_generation_id(const char *ifname, pim_addr src_addr, pim_hello_options *hello_options, uint32_t *hello_option_generation_id, uint16_t option_len, const uint8_t *tlv_curr); -int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr, +int pim_tlv_parse_addr_list(const char *ifname, pim_addr src_addr, pim_hello_options *hello_options, struct list **hello_option_addr_list, uint16_t option_len, const uint8_t *tlv_curr); -int pim_encode_addr_ucast(uint8_t *buf, struct prefix *p); +int pim_encode_addr_ucast(uint8_t *buf, pim_addr addr); +int pim_encode_addr_ucast_prefix(uint8_t *buf, struct prefix *p); int pim_encode_addr_group(uint8_t *buf, afi_t afi, int bidir, int scope, - struct in_addr group); + pim_addr group); -int pim_parse_addr_ucast(struct prefix *p, const uint8_t *buf, int buf_size); +int pim_parse_addr_ucast(pim_addr *out, const uint8_t *buf, int buf_size, + bool *wrong_af); +int pim_parse_addr_ucast_prefix(struct prefix *out, const uint8_t *buf, + int buf_size); int pim_parse_addr_group(pim_sgaddr *sg, const uint8_t *buf, int buf_size); int pim_parse_addr_source(pim_sgaddr *sg, uint8_t *flags, const uint8_t *buf, int buf_size); diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index 800ec9c45c..a410a1c2ce 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -259,11 +259,9 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim, * to INADDR_ANY. This is done in order to avoid de-registering for * 255.255.255.255 which is maintained for some reason.. */ - if (up->upstream_addr.s_addr != INADDR_ANY) { + if (!pim_addr_is_any(up->upstream_addr)) { /* Deregister addr with Zebra NHT */ - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4 = up->upstream_addr; + pim_addr_to_prefix(&nht_p, up->upstream_addr); if (PIM_DEBUG_PIM_TRACE) zlog_debug( "%s: Deregister upstream %s addr %pFX with Zebra NHT", @@ -343,8 +341,8 @@ static void join_timer_stop(struct pim_upstream *up) THREAD_OFF(up->t_join_timer); if (up->rpf.source_nexthop.interface) - nbr = pim_neighbor_find(up->rpf.source_nexthop.interface, - up->rpf.rpf_addr.u.prefix4); + nbr = pim_neighbor_find_prefix(up->rpf.source_nexthop.interface, + &up->rpf.rpf_addr); if (nbr) pim_jp_agg_remove_group(nbr->upstream_jp_agg, up, nbr); @@ -357,8 +355,8 @@ void join_timer_start(struct pim_upstream *up) struct pim_neighbor *nbr = NULL; if (up->rpf.source_nexthop.interface) { - nbr = pim_neighbor_find(up->rpf.source_nexthop.interface, - up->rpf.rpf_addr.u.prefix4); + nbr = pim_neighbor_find_prefix(up->rpf.source_nexthop.interface, + &up->rpf.rpf_addr); if (PIM_DEBUG_PIM_EVENTS) { zlog_debug( @@ -449,8 +447,8 @@ void pim_upstream_join_suppress(struct pim_upstream *up, pim_time_timer_remain_msec(up->t_join_timer); else { /* Remove it from jp agg from the nbr for suppression */ - nbr = pim_neighbor_find(up->rpf.source_nexthop.interface, - up->rpf.rpf_addr.u.prefix4); + nbr = pim_neighbor_find_prefix(up->rpf.source_nexthop.interface, + &up->rpf.rpf_addr); if (nbr) { join_timer_remain_msec = pim_time_timer_remain_msec(nbr->jp_timer); @@ -504,8 +502,8 @@ void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label, /* upstream join tracked with neighbor jp timer */ struct pim_neighbor *nbr; - nbr = pim_neighbor_find(up->rpf.source_nexthop.interface, - up->rpf.rpf_addr.u.prefix4); + nbr = pim_neighbor_find_prefix(up->rpf.source_nexthop.interface, + &up->rpf.rpf_addr); if (nbr) join_timer_remain_msec = pim_time_timer_remain_msec(nbr->jp_timer); @@ -713,7 +711,7 @@ void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up, { enum pim_upstream_state old_state = up->join_state; - if (up->upstream_addr.s_addr == INADDR_ANY) { + if (pim_addr_is_any(up->upstream_addr)) { if (PIM_DEBUG_PIM_EVENTS) zlog_debug("%s: RPF not configured for %s", __func__, up->sg_str); @@ -937,7 +935,7 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim, if (PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up->flags)) pim_upstream_keep_alive_timer_start( up, pim->keep_alive_time); - } else if (up->upstream_addr.s_addr != INADDR_ANY) { + } else if (!pim_addr_is_any(up->upstream_addr)) { pim_upstream_update_use_rpt(up, false /*update_mroute*/); rpf_result = pim_rpf_update(pim, up, NULL, __func__); @@ -1274,15 +1272,13 @@ void pim_upstream_rpf_genid_changed(struct pim_instance *pim, */ frr_each (rb_pim_upstream, &pim->upstream_head, up) { if (PIM_DEBUG_PIM_TRACE) { - char neigh_str[INET_ADDRSTRLEN]; char rpf_addr_str[PREFIX_STRLEN]; - pim_inet4_dump("<neigh?>", neigh_addr, neigh_str, - sizeof(neigh_str)); pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_addr_str, sizeof(rpf_addr_str)); zlog_debug( - "%s: matching neigh=%s against upstream (S,G)=%s[%s] joined=%d rpf_addr=%s", - __func__, neigh_str, up->sg_str, pim->vrf->name, + "%s: matching neigh=%pI4 against upstream (S,G)=%s[%s] joined=%d rpf_addr=%s", + __func__, &neigh_addr, up->sg_str, + pim->vrf->name, up->join_state == PIM_UPSTREAM_JOINED, rpf_addr_str); } @@ -1914,7 +1910,7 @@ void pim_upstream_find_new_rpf(struct pim_instance *pim) * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr */ frr_each (rb_pim_upstream, &pim->upstream_head, up) { - if (up->upstream_addr.s_addr == INADDR_ANY) { + if (pim_addr_is_any(up->upstream_addr)) { if (PIM_DEBUG_PIM_TRACE) zlog_debug( "%s: RP not configured for Upstream %s", @@ -2153,10 +2149,7 @@ void pim_upstream_remove_lhr_star_pimreg(struct pim_instance *pim, struct prefix g; enum prefix_list_type apply_new; - np = prefix_list_lookup(AFI_IP, nlist); - - g.family = AF_INET; - g.prefixlen = IPV4_MAX_BITLEN; + np = prefix_list_lookup(PIM_AFI, nlist); frr_each (rb_pim_upstream, &pim->upstream_head, up) { if (!pim_addr_is_any(up->sg.src)) @@ -2170,7 +2163,7 @@ void pim_upstream_remove_lhr_star_pimreg(struct pim_instance *pim, PIM_OIF_FLAG_PROTO_IGMP, __func__); continue; } - g.u.prefix4 = up->sg.grp; + pim_addr_to_prefix(&g, up->sg.grp); apply_new = prefix_list_apply(np, &g); if (apply_new == PREFIX_DENY) pim_channel_add_oif(up->channel_oil, pim->regiface, diff --git a/pimd/pim_util.c b/pimd/pim_util.c index decc491ede..8232d7205b 100644 --- a/pimd/pim_util.c +++ b/pimd/pim_util.c @@ -139,7 +139,7 @@ int pim_is_group_224_4(struct in_addr group_addr) return prefix_match(&group_all, &group); } -bool pim_is_group_filtered(struct pim_interface *pim_ifp, struct in_addr *grp) +bool pim_is_group_filtered(struct pim_interface *pim_ifp, pim_addr *grp) { struct prefix grp_pfx; struct prefix_list *pl; @@ -147,10 +147,8 @@ bool pim_is_group_filtered(struct pim_interface *pim_ifp, struct in_addr *grp) if (!pim_ifp->boundary_oil_plist) return false; - grp_pfx.family = AF_INET; - grp_pfx.prefixlen = IPV4_MAX_BITLEN; - grp_pfx.u.prefix4 = *grp; + pim_addr_to_prefix(&grp_pfx, *grp); - pl = prefix_list_lookup(AFI_IP, pim_ifp->boundary_oil_plist); + pl = prefix_list_lookup(PIM_AFI, pim_ifp->boundary_oil_plist); return pl ? prefix_list_apply(pl, &grp_pfx) == PREFIX_DENY : false; } diff --git a/pimd/pim_util.h b/pimd/pim_util.h index c66dd7b660..b9c227996e 100644 --- a/pimd/pim_util.h +++ b/pimd/pim_util.h @@ -35,5 +35,5 @@ void pim_pkt_dump(const char *label, const uint8_t *buf, int size); int pim_is_group_224_0_0_0_24(struct in_addr group_addr); int pim_is_group_224_4(struct in_addr group_addr); -bool pim_is_group_filtered(struct pim_interface *pim_ifp, struct in_addr *grp); +bool pim_is_group_filtered(struct pim_interface *pim_ifp, pim_addr *grp); #endif /* PIM_UTIL_H */ diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index c543c63eeb..8130aac872 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -341,13 +341,9 @@ int pim_interface_config_write(struct vty *vty) /* update source */ if (!pim_addr_is_any(pim_ifp->update_source)) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", - pim_ifp->update_source, - src_str, - sizeof(src_str)); - vty_out(vty, " ip pim use-source %s\n", - src_str); + vty_out(vty, + " ip pim use-source %pPA\n", + &pim_ifp->update_source); ++writes; } diff --git a/pimd/pim_vxlan.c b/pimd/pim_vxlan.c index c1e7be5870..39a1a32a5b 100644 --- a/pimd/pim_vxlan.c +++ b/pimd/pim_vxlan.c @@ -354,9 +354,7 @@ static void pim_vxlan_orig_mr_up_add(struct pim_vxlan_sg *vxlan_sg) * iif */ if (!PIM_UPSTREAM_FLAG_TEST_STATIC_IIF(up->flags)) { - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4 = up->upstream_addr; + pim_addr_to_prefix(&nht_p, up->upstream_addr); pim_delete_tracked_nexthop(vxlan_sg->pim, &nht_p, up, NULL); } diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 2efafd4b9b..11b13db318 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -141,12 +141,14 @@ static int pim_zebra_if_address_add(ZAPI_CALLBACK_ARGS) #endif } - if (!CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)) { - /* trying to add primary address */ - - struct in_addr primary_addr = pim_find_primary_addr(c->ifp); - if (p->family != AF_INET - || primary_addr.s_addr != p->u.prefix4.s_addr) { + if (p->family != PIM_AF) + SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY); + else if (!CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)) { + /* trying to add primary address? */ + pim_addr primary_addr = pim_find_primary_addr(c->ifp); + pim_addr addr = pim_addr_from_prefix(p); + + if (pim_addr_cmp(primary_addr, addr)) { if (PIM_DEBUG_ZEBRA) zlog_warn( "%s: %s : forcing secondary flag on %pFX", @@ -254,8 +256,8 @@ void pim_zebra_upstream_rpf_changed(struct pim_instance *pim, if (old->source_nexthop.interface) { struct pim_neighbor *nbr; - nbr = pim_neighbor_find(old->source_nexthop.interface, - old->rpf_addr.u.prefix4); + nbr = pim_neighbor_find_prefix(old->source_nexthop.interface, + &old->rpf_addr); if (nbr) pim_jp_agg_remove_group(nbr->upstream_jp_agg, up, nbr); @@ -337,8 +339,8 @@ static int pim_zebra_vxlan_sg_proc(ZAPI_CALLBACK_ARGS) s = zclient->ibuf; prefixlen = stream_getl(s); - stream_get(&sg.src.s_addr, s, prefixlen); - stream_get(&sg.grp.s_addr, s, prefixlen); + stream_get(&sg.src, s, prefixlen); + stream_get(&sg.grp, s, prefixlen); if (PIM_DEBUG_ZEBRA) zlog_debug("%u:recv SG %s %pSG", vrf_id, @@ -606,7 +608,7 @@ void igmp_source_forward_start(struct pim_instance *pim, } if (!source->source_channel_oil) { - struct in_addr vif_source; + pim_addr vif_source; struct prefix src, grp; struct pim_nexthop nexthop; struct pim_upstream *up = NULL; @@ -619,12 +621,8 @@ void igmp_source_forward_start(struct pim_instance *pim, } else { - src.family = AF_INET; - src.prefixlen = IPV4_MAX_BITLEN; - src.u.prefix4 = vif_source; // RP or Src address - grp.family = AF_INET; - grp.prefixlen = IPV4_MAX_BITLEN; - grp.u.prefix4 = sg.grp; + pim_addr_to_prefix(&src, vif_source); // RP or Src addr + pim_addr_to_prefix(&grp, sg.grp); up = pim_upstream_find(pim, &sg); if (up) { @@ -642,15 +640,11 @@ void igmp_source_forward_start(struct pim_instance *pim, pim_ecmp_fib_lookup_if_vif_index( pim, &src, &grp); - if (PIM_DEBUG_ZEBRA) { - char buf2[INET_ADDRSTRLEN]; - - pim_inet4_dump("<source?>", vif_source, buf2, - sizeof(buf2)); - zlog_debug("%s: NHT %pSG vif_source %s vif_index:%d ", - __func__, &sg, buf2, - input_iface_vif_index); - } + if (PIM_DEBUG_ZEBRA) + zlog_debug( + "%s: NHT %pSG vif_source %pPAs vif_index:%d ", + __func__, &sg, &vif_source, + input_iface_vif_index); if (input_iface_vif_index < 1) { if (PIM_DEBUG_IGMP_TRACE) { diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c index 5997cc25a4..b169335a3a 100644 --- a/pimd/pim_zlookup.c +++ b/pimd/pim_zlookup.c @@ -300,9 +300,9 @@ static int zclient_read_nexthop(struct pim_instance *pim, if (nbr) { nexthop_tab[num_ifindex].nexthop_addr.family = AF_INET; - nexthop_tab[num_ifindex] - .nexthop_addr.u.prefix4 = - nbr->source_addr; + pim_addr_to_prefix( + &nexthop_tab[num_ifindex].nexthop_addr, + nbr->source_addr); } ++num_ifindex; break; diff --git a/pimd/pimd.c b/pimd/pimd.c index 992bb931bd..9621f9794d 100644 --- a/pimd/pimd.c +++ b/pimd/pimd.c @@ -49,15 +49,22 @@ CPP_NOTICE("Work needs to be done to make this work properly via the pim mroute socket\n"); #endif /* MAXVIFS > 256 */ +#if PIM_IPV == 4 const char *const PIM_ALL_SYSTEMS = MCAST_ALL_SYSTEMS; const char *const PIM_ALL_ROUTERS = MCAST_ALL_ROUTERS; const char *const PIM_ALL_PIM_ROUTERS = MCAST_ALL_PIM_ROUTERS; const char *const PIM_ALL_IGMP_ROUTERS = MCAST_ALL_IGMP_ROUTERS; +#else +const char *const PIM_ALL_SYSTEMS = "ff02::1"; +const char *const PIM_ALL_ROUTERS = "ff02::2"; +const char *const PIM_ALL_PIM_ROUTERS = "ff02::d"; +const char *const PIM_ALL_IGMP_ROUTERS = "ff02::16"; +#endif DEFINE_MTYPE_STATIC(PIMD, ROUTER, "PIM Router information"); struct pim_router *router = NULL; -struct in_addr qpim_all_pim_routers_addr; +pim_addr qpim_all_pim_routers_addr; void pim_prefix_list_update(struct prefix_list *plist) { @@ -103,7 +110,7 @@ void pim_router_init(void) PIM_ASSERT_METRIC_PREFERENCE_MAX; router->infinite_assert_metric.route_metric = PIM_ASSERT_ROUTE_METRIC_MAX; - router->infinite_assert_metric.ip_address.s_addr = INADDR_ANY; + router->infinite_assert_metric.ip_address = PIMADDR_ANY; router->rpf_cache_refresh_delay_msec = 50; router->register_suppress_time = PIM_REGISTER_SUPPRESSION_TIME_DEFAULT; router->packet_process = PIM_DEFAULT_PACKET_PROCESS; @@ -120,7 +127,8 @@ void pim_router_terminate(void) void pim_init(void) { - if (!inet_aton(PIM_ALL_PIM_ROUTERS, &qpim_all_pim_routers_addr)) { + if (!inet_pton(PIM_AF, PIM_ALL_PIM_ROUTERS, + &qpim_all_pim_routers_addr)) { flog_err( EC_LIB_SOCKET, "%s %s: could not solve %s to group address: errno=%d: %s", diff --git a/pimd/pimd.h b/pimd/pimd.h index 7732dc5b74..d4eac58a29 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -134,7 +134,7 @@ extern const char *const PIM_ALL_PIM_ROUTERS; extern const char *const PIM_ALL_IGMP_ROUTERS; extern struct zebra_privs_t pimd_privs; -extern struct in_addr qpim_all_pim_routers_addr; +extern pim_addr qpim_all_pim_routers_addr; extern uint8_t qpim_ecmp_enable; extern uint8_t qpim_ecmp_rebalance_enable; diff --git a/tests/bgpd/test_aspath.c b/tests/bgpd/test_aspath.c index c2d39752ab..7288dc0869 100644 --- a/tests/bgpd/test_aspath.c +++ b/tests/bgpd/test_aspath.c @@ -1062,8 +1062,7 @@ static void parse_test(struct test_segment *t) printf("\n"); - if (asp) - aspath_unintern(&asp); + aspath_unintern(&asp); } /* prepend testing */ @@ -1117,8 +1116,7 @@ static void empty_prepend_test(struct test_segment *t) printf(FAILED "!\n"); printf("\n"); - if (asp1) - aspath_unintern(&asp1); + aspath_unintern(&asp1); aspath_free(asp2); } @@ -1277,10 +1275,8 @@ static int handle_attr_test(struct aspath_tests *t) } out: - if (attr.aspath) - aspath_unintern(&attr.aspath); - if (asp) - aspath_unintern(&asp); + aspath_unintern(&attr.aspath); + aspath_unintern(&asp); return failed - initfail; } diff --git a/tests/topotests/bgp_route_map/test_route_map_topo1.py b/tests/topotests/bgp_route_map/test_route_map_topo1.py index 3c2d7f28a2..6556c050bb 100644 --- a/tests/topotests/bgp_route_map/test_route_map_topo1.py +++ b/tests/topotests/bgp_route_map/test_route_map_topo1.py @@ -444,9 +444,10 @@ def test_route_map_inbound_outbound_same_neighbor_p0(request): result = verify_rib( tgen, adt, dut, input_dict_2, protocol=protocol, expected=False ) - assert result is not True, ( - "Testcase {} : Failed \n" - "routes are not present in rib \n Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \nroutes are not present in rib \n Error: {}".format( + tc_name, result ) logger.info("Expected behaviour: {}".format(result)) @@ -466,9 +467,10 @@ def test_route_map_inbound_outbound_same_neighbor_p0(request): result = verify_rib( tgen, adt, dut, input_dict, protocol=protocol, expected=False ) - assert result is not True, ( - "Testcase {} : Failed \n " - "routes are not present in rib \n Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \nroutes are not present in rib \n Error: {}".format( + tc_name, result ) logger.info("Expected behaviour: {}".format(result)) @@ -664,9 +666,10 @@ def test_route_map_with_action_values_combination_of_prefix_action_p0( result = verify_rib( tgen, adt, dut, input_dict_2, protocol=protocol, expected=False ) - assert result is not True, ( - "Testcase {} : Failed \n " - "Routes are still present \n Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \nRoutes are still present \n Error: {}".format( + tc_name, result ) logger.info("Expected behaviour: {}".format(result)) else: diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index 551483d718..34afa0d2c1 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -3677,7 +3677,7 @@ def verify_f_bit(tgen, topo, addr_type, input_dict, dut, peer, expected=True): @retry(retry_timeout=10) def verify_graceful_restart_timers(tgen, topo, addr_type, input_dict, dut, peer): """ - This API is to verify graceful restart timers, configured and recieved + This API is to verify graceful restart timers, configured and received Parameters ---------- diff --git a/tests/topotests/lib/ospf.py b/tests/topotests/lib/ospf.py index 92d29ad1ab..8d2bf12af2 100644 --- a/tests/topotests/lib/ospf.py +++ b/tests/topotests/lib/ospf.py @@ -1933,7 +1933,7 @@ def verify_ospf6_interface(tgen, topo=None, dut=None, lan=False, input_dict=None True or False (Error Message) """ - logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name)) + logger.debug("Entering lib API: verify_ospf6_interface") result = False if topo is None: @@ -2311,6 +2311,7 @@ def config_ospf6_interface( ------- True or False """ + logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name)) result = False if topo is None: @@ -2337,6 +2338,7 @@ def config_ospf6_interface( ospf_data = input_dict[router]["links"][lnk]["ospf6"] data_ospf_area = ospf_data.setdefault("area", None) data_ospf_auth = ospf_data.setdefault("hash-algo", None) + data_ospf_keychain = ospf_data.setdefault("keychain", None) data_ospf_dr_priority = ospf_data.setdefault("priority", None) data_ospf_cost = ospf_data.setdefault("cost", None) data_ospf_mtu = ospf_data.setdefault("mtu_ignore", None) @@ -2369,9 +2371,18 @@ def config_ospf6_interface( ospf_data["hash-algo"], ospf_data["key"], ) - if "del_action" in ospf_data: - cmd = "no {}".format(cmd) - config_data.append(cmd) + config_data.append(cmd) + + # interface ospf auth with keychain + if data_ospf_keychain: + cmd = "ipv6 ospf6 authentication" + + if "del_action" in ospf_data: + cmd = "no {}".format(cmd) + + if "keychain" in ospf_data: + cmd = "{} keychain {}".format(cmd, ospf_data["keychain"]) + config_data.append(cmd) # interface ospf dr priority if data_ospf_dr_priority: diff --git a/tests/topotests/multicast_pim_bsm_topo1/test_mcast_pim_bsmp_01.py b/tests/topotests/multicast_pim_bsm_topo1/test_mcast_pim_bsmp_01.py index a8418d400d..4ab160b52e 100644 --- a/tests/topotests/multicast_pim_bsm_topo1/test_mcast_pim_bsmp_01.py +++ b/tests/topotests/multicast_pim_bsm_topo1/test_mcast_pim_bsmp_01.py @@ -501,7 +501,7 @@ def test_BSR_higher_prefer_ip_p0(request): step("sleeping for 3 sec to leran new packet") do_countdown(3) - step("verify BSR1 is become prefered RP") + step("verify BSR1 has become preferred RP") dut = "l1" step("Verify if b1 chosen as BSR in f1") @@ -521,7 +521,7 @@ def test_BSR_higher_prefer_ip_p0(request): do_countdown(3) f1_b2_eth1 = topo["routers"]["f1"]["links"]["b2"]["interface"] shutdown_bringup_interface(tgen, "f1", "f1-b2-eth1", True) - step("verify BSR2 is become prefered RP") + step("verify BSR2 has become preferred RP") dut = "l1" step("Send BSR packet from b1 and b2 to FHR") diff --git a/tests/topotests/ospfv3_basic_functionality/ospfv3_authentication.json b/tests/topotests/ospfv3_basic_functionality/ospfv3_authentication.json new file mode 100644 index 0000000000..08ff253b75 --- /dev/null +++ b/tests/topotests/ospfv3_basic_functionality/ospfv3_authentication.json @@ -0,0 +1,169 @@ +{ + "address_types": [ + "ipv6" + ], + "ipv6base": "fd00::", + "ipv6mask": 64, + "link_ip_start": { + "ipv6": "fd00::", + "v6mask": 64 + }, + "lo_prefix": { + "ipv6": "2001:db8:f::", + "v6mask": 128 + }, + "routers": { + "r0": { + "links": { + "r1": { + "ipv6": "auto", + "ospf6": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4 + } + }, + "r2": { + "ipv6": "auto", + "ospf6": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4 + } + }, + "r3": { + "ipv6": "auto", + "ospf6": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4 + } + } + }, + "ospf6": { + "router_id": "100.1.1.0", + "neighbors": { + "r1": {}, + "r2": {}, + "r3": {} + }, + "redistribute": [ + { + "redist_type": "static" + }, + { + "redist_type": "connected" + } + ] + } + }, + "r1": { + "links": { + "r0": { + "ipv6": "auto", + "ospf6": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4 + } + }, + "r2": { + "ipv6": "auto", + "ospf6": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4 + } + }, + "r3": { + "ipv6": "auto", + "ospf6": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4 + } + } + }, + "ospf6": { + "router_id": "100.1.1.1", + "neighbors": { + "r0": {}, + "r2": {}, + "r3": {} + } + } + }, + "r2": { + "links": { + "r0": { + "ipv6": "auto", + "ospf6": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4 + } + }, + "r1": { + "ipv6": "auto", + "ospf6": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4 + } + }, + "r3": { + "ipv6": "auto", + "ospf6": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4 + } + } + }, + "ospf6": { + "router_id": "100.1.1.2", + "neighbors": { + "r1": {}, + "r0": {}, + "r3": {} + } + } + }, + "r3": { + "links": { + "r0": { + "ipv6": "auto", + "ospf6": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4 + } + }, + "r1": { + "ipv6": "auto", + "ospf6": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4 + } + }, + "r2": { + "ipv6": "auto", + "ospf6": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4 + } + } + }, + "ospf6": { + "router_id": "100.1.1.3", + "neighbors": { + "r0": {}, + "r1": {}, + "r2": {} + } + } + } + } +}
\ No newline at end of file diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_authentication.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_authentication.py new file mode 100644 index 0000000000..baa0071f9c --- /dev/null +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_authentication.py @@ -0,0 +1,1446 @@ +#!/usr/bin/python + +# +# Copyright (c) 2021 by VMware, Inc. ("VMware") +# Used Copyright (c) 2018 by Network Device Education Foundation, Inc. +# ("NetDEF") in this file. +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + + +"""OSPF Basic Functionality Automation.""" +import os +import sys +import time +import pytest +from time import sleep +from copy import deepcopy +import json +from lib.topotest import frr_unicode + +pytestmark = pytest.mark.ospf6d + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) +sys.path.append(os.path.join(CWD, "../lib/")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib.topogen import Topogen, get_topogen + +# Import topoJson from lib, to create topology and initial configuration +from lib.common_config import ( + start_topology, + write_test_header, + write_test_footer, + reset_config_on_routers, + step, + shutdown_bringup_interface, + topo_daemons, +) +from lib.topolog import logger +from lib.topojson import build_topo_from_json, build_config_from_json +from lib.ospf import verify_ospf6_neighbor, config_ospf6_interface, clear_ospf +from ipaddress import IPv4Address + +# Global variables +topo = None +# Reading the data from JSON File for topology creation +jsonFile = "{}/ospfv3_authentication.json".format(CWD) +try: + with open(jsonFile, "r") as topoJson: + topo = json.load(topoJson) +except IOError: + assert False, "Could not read file {}".format(jsonFile) +""" +TOPOOLOGY = + Please view in a fixed-width font such as Courier. + +---+ A1 +---+ + +R1 +------------+R2 | + +-+-+- +--++ + | -- -- | + | -- A0 -- | + A0| ---- | + | ---- | A2 + | -- -- | + | -- -- | + +-+-+- +-+-+ + +R0 +-------------+R3 | + +---+ A3 +---+ + +TESTCASES = +1. OSPFv3 Authentication Trailer - Verify ospfv3 authentication trailer + using MD5 manual key configuration. +2. OSPFv3 Authentication Trailer - Verify ospfv3 authentication trailer + using HMAC-SHA-256 manual key configuration. +3. OSPFv3 Authentication Trailer - Verify ospfv3 authentication trailer + using MD5 keychain configuration. +4. OSPFv3 Authentication Trailer - Verify ospfv3 authentication trailer + using HMAC-SHA-256 keychain configuration. + + """ + +def setup_module(mod): + """ + Sets up the pytest environment + * `mod`: module name + """ + testsuite_run_time = time.asctime(time.localtime(time.time())) + logger.info("Testsuite start time: {}".format(testsuite_run_time)) + logger.info("=" * 40) + + logger.info("Running setup_module to create topology") + + # This function initiates the topology build with Topogen... + json_file = "{}/ospfv3_single_area.json".format(CWD) + tgen = Topogen(json_file, mod.__name__) + global topo + topo = tgen.json_topo + # ... and here it calls Mininet initialization functions. + + # get list of daemons needs to be started for this suite. + daemons = topo_daemons(tgen, topo) + + # Starting topology, create tmp files which are loaded to routers + # to start deamons and then start routers + start_topology(tgen, daemons) + + # Creating configuration from JSON + build_config_from_json(tgen, topo) + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + ospf6_covergence = verify_ospf6_neighbor(tgen, topo) + assert ospf6_covergence is True, "setup_module :Failed \n Error:" " {}".format( + ospf6_covergence + ) + + logger.info("Running setup_module() done") + + +def teardown_module(mod): + """ + Teardown the pytest environment. + * `mod`: module name + """ + + logger.info("Running teardown_module to delete topology") + + tgen = get_topogen() + + # Stop toplogy and Remove tmp files + tgen.stop_topology() + + logger.info( + "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) + ) + logger.info("=" * 40) + + +# ################################## +# Test cases start here. +# ################################## + +def test_ospf6_auth_trailer_tc1_md5(request): + """ + OSPFv3 Authentication Trailer - Verify ospfv3 authentication trailer + using MD5 manual key configuration. + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + global topo + step("Bring up the base config.") + reset_config_on_routers(tgen) + step( + "Configure ospf6 between R1 and R2, enable ospf6 auth on R1 interface " + "connected to R2 with auth trailer" + ) + + r1_ospf6_auth = { + "r1": { + "links": { + "r2": { + "ospf6": { + "hash-algo": "md5", + "key": "ospf6", + "key-id": "10", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify that the neighbour is not FULL between R1 and R2.") + # wait for dead time expiry. + sleep(6) + dut = "r1" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=3 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Configure ospf6 between R1 and R2, enable ospf6 on R2 interface " + "connected to R1 with auth trailer" + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "hash-algo": "md5", + "key": "ospf6", + "key-id": "10", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbour is FULL between R1 and R2 " + "using show ipv6 ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Disable authentication on R2 " + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "hash-algo": "md5", + "key": "ospf6", + "key-id": "10", + "del_action": True + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify on R1 ,nbr is deleted for R2 after dead interval expiry") + # wait till the dead timer expiry + sleep(6) + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=5 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step("Again On R2 enable ospf6 on interface with message-digest auth") + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "hash-algo": "md5", + "key": "ospf6", + "key-id": "10", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbour is FULL between R1 and R2 using" + " show ip ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step("Shut no shut interface on R1") + dut = "r1" + intf = topo["routers"]["r1"]["links"]["r2"]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + + dut = "r2" + step( + "Verify that the neighbour is not FULL between R1 and R2 using " + "show ip ospf6 neighbor cmd." + ) + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut, expected=False) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + dut = "r1" + shutdown_bringup_interface(tgen, dut, intf, True) + + step( + "Verify that the neighbour is FULL between R1 and R2 using " + "show ip ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + write_test_footer(tc_name) + + +def test_ospf6_auth_trailer_tc2_sha256(request): + """ + OSPFv3 Authentication Trailer - Verify ospfv3 authentication trailer + using HMAC-SHA-256 manual key configuration. + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + global topo + step("Bring up the base config.") + reset_config_on_routers(tgen) + step( + "Configure ospf6 between R1 and R2, enable ospf6 auth on R1 interface " + "connected to R2 with auth trailer" + ) + + r1_ospf6_auth = { + "r1": { + "links": { + "r2": { + "ospf6": { + "hash-algo": "hmac-sha-256", + "key": "ospf6", + "key-id": "10", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify that the neighbour is not FULL between R1 and R2.") + # wait for dead time expiry. + sleep(6) + dut = "r1" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=3 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Configure ospf6 between R1 and R2, enable ospf6 on R2 interface " + "connected to R1 with auth trailer" + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "hash-algo": "hmac-sha-256", + "key": "ospf6", + "key-id": "10", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbour is FULL between R1 and R2 " + "using show ipv6 ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Disable authentication on R2 " + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "hash-algo": "hmac-sha-256", + "key": "ospf6", + "key-id": "10", + "del_action": True + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify on R1 ,nbr is deleted for R2 after dead interval expiry") + # wait till the dead timer expiry + sleep(6) + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=5 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step("Again On R2 enable ospf6 on interface with message-digest auth") + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "hash-algo": "hmac-sha-256", + "key": "ospf6", + "key-id": "10", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbour is FULL between R1 and R2 using" + " show ip ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step("Shut no shut interface on R1") + dut = "r1" + intf = topo["routers"]["r1"]["links"]["r2"]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + + dut = "r2" + step( + "Verify that the neighbour is not FULL between R1 and R2 using " + "show ip ospf6 neighbor cmd." + ) + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut, expected=False) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + dut = "r1" + shutdown_bringup_interface(tgen, dut, intf, True) + + step( + "Verify that the neighbour is FULL between R1 and R2 using " + "show ip ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + write_test_footer(tc_name) + +def test_ospf6_auth_trailer_tc3_keychain_md5(request): + """ + OSPFv3 Authentication Trailer - Verify ospfv3 authentication trailer + using MD5 keychain configuration. + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + global topo + step("Bring up the base config.") + reset_config_on_routers(tgen) + step( + "Configure ospf6 between R1 and R2, enable ospf6 auth on R1 interface " + "connected to R2 with auth trailer" + ) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + + router1.vtysh_cmd( + """configure terminal + key chain auth + key 10 + key-string ospf6 + cryptographic-algorithm md5""" + ) + + router2.vtysh_cmd( + """configure terminal + key chain auth + key 10 + key-string ospf6 + cryptographic-algorithm md5""" + ) + + r1_ospf6_auth = { + "r1": { + "links": { + "r2": { + "ospf6": { + "keychain": "auth", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify that the neighbour is not FULL between R1 and R2.") + # wait for dead time expiry. + sleep(6) + dut = "r1" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=3 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Configure ospf6 between R1 and R2, enable ospf6 on R2 interface " + "connected to R1 with auth trailer" + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "keychain": "auth", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbour is FULL between R1 and R2 " + "using show ipv6 ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Disable authentication on R2 " + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "keychain": "auth", + "del_action": True + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify on R1 ,nbr is deleted for R2 after dead interval expiry") + # wait till the dead timer expiry + sleep(6) + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=5 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step("Again On R2 enable ospf6 on interface with message-digest auth") + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "keychain": "auth", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbour is FULL between R1 and R2 using" + " show ip ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step("Shut no shut interface on R1") + dut = "r1" + intf = topo["routers"]["r1"]["links"]["r2"]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + + dut = "r2" + step( + "Verify that the neighbour is not FULL between R1 and R2 using " + "show ip ospf6 neighbor cmd." + ) + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut, expected=False) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + dut = "r1" + shutdown_bringup_interface(tgen, dut, intf, True) + + step( + "Verify that the neighbour is FULL between R1 and R2 using " + "show ip ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + write_test_footer(tc_name) + +def test_ospf6_auth_trailer_tc4_keychain_sha256(request): + """ + OSPFv3 Authentication Trailer - Verify ospfv3 authentication trailer + using HMAC-SHA-256 keychain configuration. + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + global topo + step("Bring up the base config.") + reset_config_on_routers(tgen) + step( + "Configure ospf6 between R1 and R2, enable ospf6 auth on R1 interface " + "connected to R2 with auth trailer" + ) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + + router1.vtysh_cmd( + """configure terminal + key chain auth + key 10 + key-string ospf6 + cryptographic-algorithm hmac-sha-256""" + ) + + router2.vtysh_cmd( + """configure terminal + key chain auth + key 10 + key-string ospf6 + cryptographic-algorithm hmac-sha-256""" + ) + + r1_ospf6_auth = { + "r1": { + "links": { + "r2": { + "ospf6": { + "keychain": "auth", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify that the neighbour is not FULL between R1 and R2.") + # wait for dead time expiry. + sleep(6) + dut = "r1" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=3 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Configure ospf6 between R1 and R2, enable ospf6 on R2 interface " + "connected to R1 with auth trailer" + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "keychain": "auth", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbour is FULL between R1 and R2 " + "using show ipv6 ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Disable authentication on R2 " + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "keychain": "auth", + "del_action": True + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify on R1 ,nbr is deleted for R2 after dead interval expiry") + # wait till the dead timer expiry + sleep(6) + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=5 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step("Again On R2 enable ospf6 on interface with message-digest auth") + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "keychain": "auth", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbour is FULL between R1 and R2 using" + " show ip ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step("Shut no shut interface on R1") + dut = "r1" + intf = topo["routers"]["r1"]["links"]["r2"]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + + dut = "r2" + step( + "Verify that the neighbour is not FULL between R1 and R2 using " + "show ip ospf6 neighbor cmd." + ) + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut, expected=False) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + dut = "r1" + shutdown_bringup_interface(tgen, dut, intf, True) + + step( + "Verify that the neighbour is FULL between R1 and R2 using " + "show ip ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + write_test_footer(tc_name) + +def test_ospf6_auth_trailer_tc5_md5_keymissmatch(request): + """ + OSPFv3 Authentication Trailer - Verify ospfv3 authentication trailer + using MD5 manual key configuration. + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + global topo + step("Bring up the base config.") + reset_config_on_routers(tgen) + step( + "Configure ospf6 between R1 and R2, enable ospf6 auth on R1 interface " + "connected to R2 with auth trailer" + ) + + r1_ospf6_auth = { + "r1": { + "links": { + "r2": { + "ospf6": { + "hash-algo": "md5", + "key": "ospf6", + "key-id": "10", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify that the neighbour is not FULL between R1 and R2.") + # wait for dead time expiry. + sleep(6) + dut = "r1" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=3 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Configure ospf6 between R1 and R2, enable ospf6 on R2 interface " + "connected to R1 with auth trailer wrong key" + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "hash-algo": "md5", + "key": "ospf6-missmatch", + "key-id": "10", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbour is not FULL between R1 and R2 " + "using show ipv6 ospf6 neighbor cmd." + ) + + step("Verify that the neighbour is FULL between R1 and R2.") + # wait for dead time expiry. + sleep(6) + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=3 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Configure ospf6 between R1 and R2, enable ospf6 on R2 interface " + "connected to R1 with auth trailer correct key" + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "hash-algo": "md5", + "key": "ospf6", + "key-id": "10", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbour is FULL between R1 and R2 " + "using show ipv6 ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + write_test_footer(tc_name) + +def test_ospf6_auth_trailer_tc6_sha256_mismatch(request): + """ + OSPFv3 Authentication Trailer - Verify ospfv3 authentication trailer + using HMAC-SHA-256 manual key configuration. + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + global topo + step("Bring up the base config.") + reset_config_on_routers(tgen) + step( + "Configure ospf6 between R1 and R2, enable ospf6 auth on R1 interface " + "connected to R2 with auth trailer" + ) + + r1_ospf6_auth = { + "r1": { + "links": { + "r2": { + "ospf6": { + "hash-algo": "hmac-sha-256", + "key": "ospf6", + "key-id": "10", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify that the neighbour is not FULL between R1 and R2.") + # wait for dead time expiry. + sleep(6) + dut = "r1" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=3 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Configure ospf6 with on R1 and R2, enable ospf6 on R2 interface " + "connected to R1 with auth trailer wrong key" + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "hash-algo": "hmac-sha-256", + "key": "ospf6-missmatch", + "key-id": "10", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify that the neighbour is not FULL between R1 and R2.") + # wait for dead time expiry. + sleep(6) + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=3 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Configure ospf6 with on R1 and R2, enable ospf6 on R2 interface " + "connected to R1 with auth trailer wrong key" + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "hash-algo": "hmac-sha-256", + "key": "ospf6", + "key-id": "10", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbour is FULL between R1 and R2 " + "using show ipv6 ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + write_test_footer(tc_name) + +def test_ospf6_auth_trailer_tc7_keychain_md5_missmatch(request): + """ + OSPFv3 Authentication Trailer - Verify ospfv3 authentication trailer + using MD5 keychain configuration. + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + global topo + step("Bring up the base config.") + reset_config_on_routers(tgen) + step( + "Configure ospf6 between R1 and R2, enable ospf6 auth on R1 interface " + "connected to R2 with auth trailer" + ) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + + router1.vtysh_cmd( + """configure terminal + key chain auth + key 10 + key-string ospf6 + cryptographic-algorithm md5""" + ) + + router2.vtysh_cmd( + """configure terminal + key chain auth + key 10 + key-string ospf6 + cryptographic-algorithm md5""" + ) + + router2.vtysh_cmd( + """configure terminal + key chain auth-missmatch + key 10 + key-string ospf6-missmatch + cryptographic-algorithm md5""" + ) + + r1_ospf6_auth = { + "r1": { + "links": { + "r2": { + "ospf6": { + "keychain": "auth", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify that the neighbour is not FULL between R1 and R2.") + # wait for dead time expiry. + sleep(6) + dut = "r1" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=3 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Configure ospf6 between R1 and R2, enable ospf6 on R2 interface " + "connected to R1 with auth trailer with wrong keychain" + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "keychain": "auth-missmatch", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify that the neighbour is not FULL between R1 and R2.") + # wait for dead time expiry. + sleep(6) + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=3 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Configure ospf6 between R1 and R2, enable ospf6 on R2 interface " + "connected to R1 with auth trailer with correct keychain" + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "keychain": "auth", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbour is FULL between R1 and R2 " + "using show ipv6 ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + write_test_footer(tc_name) + +def test_ospf6_auth_trailer_tc8_keychain_sha256_missmatch(request): + """ + OSPFv3 Authentication Trailer - Verify ospfv3 authentication trailer + using HMAC-SHA-256 keychain configuration. + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + global topo + step("Bring up the base config.") + reset_config_on_routers(tgen) + step( + "Configure ospf6 between R1 and R2, enable ospf6 auth on R1 interface " + "connected to R2 with auth trailer" + ) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + + router1.vtysh_cmd( + """configure terminal + key chain auth + key 10 + key-string ospf6 + cryptographic-algorithm hmac-sha-256""" + ) + + router2.vtysh_cmd( + """configure terminal + key chain auth + key 10 + key-string ospf6 + cryptographic-algorithm hmac-sha-256""" + ) + + router2.vtysh_cmd( + """configure terminal + key chain auth-missmatch + key 10 + key-string ospf6-missmatch + cryptographic-algorithm hmac-sha-256""" + ) + + r1_ospf6_auth = { + "r1": { + "links": { + "r2": { + "ospf6": { + "keychain": "auth", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify that the neighbour is not FULL between R1 and R2.") + # wait for dead time expiry. + sleep(6) + dut = "r1" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=3 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Configure ospf6 between R1 and R2, enable ospf6 on R2 interface " + "connected to R1 with auth trailer wrong keychain" + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "keychain": "auth-missmatch", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify that the neighbour is not FULL between R1 and R2.") + # wait for dead time expiry. + sleep(6) + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=3 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Configure ospf6 between R1 and R2, enable ospf6 on R2 interface " + "connected to R1 with auth trailer correct keychain" + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "keychain": "auth", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbour is FULL between R1 and R2 " + "using show ipv6 ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + write_test_footer(tc_name) + +def test_ospf6_auth_trailer_tc9_keychain_not_configured(request): + """ + OSPFv3 Neighborship without Authentication Trailer - + Verify ospfv3 neighborship when no authentication trailer is configured. + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + global topo + step("Bring up the base config.") + reset_config_on_routers(tgen) + step( + "Configure ospf6 between R1 and R2, enable ospf6 auth on R1 interface " + "connected to R2 with auth trailer" + ) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + + r1_ospf6_auth = { + "r1": { + "links": { + "r2": { + "ospf6": { + "keychain": "auth", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify that the neighbour is not FULL between R1 and R2.") + # wait for dead time expiry. + sleep(6) + dut = "r1" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=3 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Configure ospf6 between R1 and R2, enable ospf6 on R2 interface " + "connected to R1 with auth trailer non existing keychain" + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "keychain": "auth", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify that the neighbour is not FULL between R1 and R2.") + # wait for dead time expiry. + sleep(6) + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=3 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + write_test_footer(tc_name) + +def test_ospf6_auth_trailer_tc10_no_auth_trailer(request): + """ + OSPFv3 Neighborship without Authentication Trailer - + Verify ospfv3 neighborship when no authentication trailer is configured. + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + global topo + step("Bring up the base config.") + reset_config_on_routers(tgen) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + + step( + "Verify that the neighbour is FULL between R1 and R2 " + "using show ipv6 ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + write_test_footer(tc_name) + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in index 334bd7affa..c2b4e779de 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -91,7 +91,7 @@ sub scan_file { # $protocol is VTYSH_PROTO format for redirection of user input if ($file =~ /lib\/keychain\.c$/) { - $protocol = "VTYSH_RIPD|VTYSH_EIGRPD"; + $protocol = "VTYSH_RIPD|VTYSH_EIGRPD|VTYSH_OSPF6D"; } elsif ($file =~ /lib\/routemap\.c$/ || $file =~ /lib\/routemap_cli\.c$/) { $protocol = "VTYSH_RMAP"; diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 8e95aaa47c..336fe8b30e 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -818,7 +818,7 @@ int vtysh_mark_file(const char *filename) return 0; } -/* Configration make from file. */ +/* Configuration make from file. */ int vtysh_config_from_file(struct vty *vty, FILE *fp) { int ret; @@ -1586,7 +1586,7 @@ DEFUNSH(VTYSH_REALLYALL, vtysh_end_all, vtysh_end_all_cmd, "end", DEFUNSH(VTYSH_ZEBRA, srv6, srv6_cmd, "srv6", - "Segment-Routing SRv6 configration\n") + "Segment-Routing SRv6 configuration\n") { vty->node = SRV6_NODE; return CMD_SUCCESS; @@ -1594,7 +1594,7 @@ DEFUNSH(VTYSH_ZEBRA, srv6, srv6_cmd, DEFUNSH(VTYSH_ZEBRA, srv6_locators, srv6_locators_cmd, "locators", - "Segment-Routing SRv6 locators configration\n") + "Segment-Routing SRv6 locators configuration\n") { vty->node = SRV6_LOCS_NODE; return CMD_SUCCESS; diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h index e56d482da2..66af248354 100644 --- a/vtysh/vtysh.h +++ b/vtysh/vtysh.h @@ -57,7 +57,7 @@ DECLARE_MGROUP(MVTYSH); #define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_FABRICD #define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_PBRD|VTYSH_FABRICD|VTYSH_VRRPD #define VTYSH_VRF VTYSH_INTERFACE|VTYSH_STATICD -#define VTYSH_KEYS VTYSH_RIPD|VTYSH_EIGRPD +#define VTYSH_KEYS VTYSH_RIPD | VTYSH_EIGRPD | VTYSH_OSPF6D /* Daemons who can process nexthop-group configs */ #define VTYSH_NH_GROUP VTYSH_PBRD|VTYSH_SHARPD #define VTYSH_SR VTYSH_ZEBRA|VTYSH_PATHD diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c index 76956574cc..a4f27b61cb 100644 --- a/vtysh/vtysh_main.c +++ b/vtysh/vtysh_main.c @@ -587,7 +587,7 @@ int main(int argc, char **argv, char **env) * Setup history file for use by both -c and regular input * If we can't find the home directory, then don't store * the history information. - * VTYSH_HISTFILE is prefered over command line + * VTYSH_HISTFILE is preferred over command line * argument (-H/--histfile). */ if (getenv("VTYSH_HISTFILE")) { diff --git a/yang/frr-pathd.yang b/yang/frr-pathd.yang index 30f9875a6d..5beda769c1 100644 --- a/yang/frr-pathd.yang +++ b/yang/frr-pathd.yang @@ -414,7 +414,7 @@ module frr-pathd { container objective-function { presence "If the candidate has an objective function constraint"; description - "Define objective function constraint as a list of prefered functions"; + "Define objective function constraint as a list of preferred functions"; leaf required { type boolean; default "true"; diff --git a/zebra/debug_nl.c b/zebra/debug_nl.c index 0e0ccccb6a..825497fff3 100644 --- a/zebra/debug_nl.c +++ b/zebra/debug_nl.c @@ -24,6 +24,7 @@ #include <linux/nexthop.h> #include <linux/rtnetlink.h> #include <net/if_arp.h> +#include <linux/fib_rules.h> #include <stdio.h> #include <stdint.h> @@ -576,6 +577,86 @@ const char *nhm_rta2str(int type) } } +const char *frh_rta2str(int type) +{ + switch (type) { + case FRA_DST: + return "DST"; + case FRA_SRC: + return "SRC"; + case FRA_IIFNAME: + return "IIFNAME"; + case FRA_GOTO: + return "GOTO"; + case FRA_UNUSED2: + return "UNUSED2"; + case FRA_PRIORITY: + return "PRIORITY"; + case FRA_UNUSED3: + return "UNUSED3"; + case FRA_UNUSED4: + return "UNUSED4"; + case FRA_UNUSED5: + return "UNUSED5"; + case FRA_FWMARK: + return "FWMARK"; + case FRA_FLOW: + return "FLOW"; + case FRA_TUN_ID: + return "TUN_ID"; + case FRA_SUPPRESS_IFGROUP: + return "SUPPRESS_IFGROUP"; + case FRA_SUPPRESS_PREFIXLEN: + return "SUPPRESS_PREFIXLEN"; + case FRA_TABLE: + return "TABLE"; + case FRA_FWMASK: + return "FWMASK"; + case FRA_OIFNAME: + return "OIFNAME"; + case FRA_PAD: + return "PAD"; + case FRA_L3MDEV: + return "L3MDEV"; + case FRA_UID_RANGE: + return "UID_RANGE"; + case FRA_PROTOCOL: + return "PROTOCOL"; + case FRA_IP_PROTO: + return "IP_PROTO"; + case FRA_SPORT_RANGE: + return "SPORT_RANGE"; + case FRA_DPORT_RANGE: + return "DPORT_RANGE"; + default: + return "UNKNOWN"; + } +} + +const char *frh_action2str(uint8_t action) +{ + switch (action) { + case FR_ACT_TO_TBL: + return "TO_TBL"; + case FR_ACT_GOTO: + return "GOTO"; + case FR_ACT_NOP: + return "NOP"; + case FR_ACT_RES3: + return "RES3"; + case FR_ACT_RES4: + return "RES4"; + case FR_ACT_BLACKHOLE: + return "BLACKHOLE"; + case FR_ACT_UNREACHABLE: + return "UNREACHABLE"; + case FR_ACT_PROHIBIT: + return "PROHIBIT"; + default: + return "UNKNOWN"; + } +} + static inline void flag_write(int flags, int flag, const char *flagstr, char *buf, size_t buflen) { @@ -1110,6 +1191,111 @@ next_rta: goto next_rta; } +static void nlrule_dump(struct fib_rule_hdr *frh, size_t msglen) +{ + struct rtattr *rta; + size_t plen; + uint8_t u8v; + uint32_t u32v; + int32_t s32v; + uint64_t u64v; + char dbuf[128]; + struct fib_rule_uid_range *u_range; + struct fib_rule_port_range *p_range; + + /* Get the first attribute and go from there. */ + rta = RTM_RTA(frh); +next_rta: + /* Check the header for valid length and for outbound access. */ + if (RTA_OK(rta, msglen) == 0) + return; + + plen = RTA_PAYLOAD(rta); + zlog_debug(" rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len, + plen, rta->rta_type, frh_rta2str(rta->rta_type)); + switch (rta->rta_type) { + case FRA_DST: + case FRA_SRC: + switch (plen) { + case sizeof(struct in_addr): + zlog_debug(" %pI4", + (struct in_addr *)RTA_DATA(rta)); + break; + case sizeof(struct in6_addr): + zlog_debug(" %pI6", + (struct in6_addr *)RTA_DATA(rta)); + break; + default: + break; + } + break; + + case FRA_IIFNAME: + case FRA_OIFNAME: + snprintf(dbuf, sizeof(dbuf), "%s", (char *)RTA_DATA(rta)); + zlog_debug(" %s", dbuf); + break; + + case FRA_GOTO: + case FRA_UNUSED2: + case FRA_PRIORITY: + case FRA_UNUSED3: + case FRA_UNUSED4: + case FRA_UNUSED5: + case FRA_FWMARK: + case FRA_FLOW: + case FRA_TABLE: + case FRA_FWMASK: + u32v = *(uint32_t *)RTA_DATA(rta); + zlog_debug(" %u", u32v); + break; + + case FRA_SUPPRESS_IFGROUP: + case FRA_SUPPRESS_PREFIXLEN: + s32v = *(int32_t *)RTA_DATA(rta); + zlog_debug(" %d", s32v); + break; + + case FRA_TUN_ID: + u64v = *(uint64_t *)RTA_DATA(rta); + zlog_debug(" %" PRIu64, u64v); + break; + + case FRA_L3MDEV: + case FRA_PROTOCOL: + case FRA_IP_PROTO: + u8v = *(uint8_t *)RTA_DATA(rta); + zlog_debug(" %u", u8v); + break; + + case FRA_UID_RANGE: + u_range = (struct fib_rule_uid_range *)RTA_DATA(rta); + if (u_range->start == u_range->end) + zlog_debug(" %u", u_range->start); + else + zlog_debug(" %u-%u", u_range->start, u_range->end); + break; + + case FRA_SPORT_RANGE: + case FRA_DPORT_RANGE: + p_range = (struct fib_rule_port_range *)RTA_DATA(rta); + if (p_range->start == p_range->end) + zlog_debug(" %u", p_range->start); + else + zlog_debug(" %u-%u", p_range->start, p_range->end); + break; + + case FRA_PAD: /* fallthrough */ + default: + /* NOTHING: unhandled. */ + break; + } + + /* Get next pointer and start iteration again. */ + rta = RTA_NEXT(rta, msglen); + goto next_rta; +} + void nl_dump(void *msg, size_t msglen) { struct nlmsghdr *nlmsg = msg; @@ -1120,6 +1306,7 @@ void nl_dump(void *msg, size_t msglen) struct rtmsg *rtm; struct nhmsg *nhm; struct ifinfomsg *ifi; + struct fib_rule_hdr *frh; char fbuf[128]; char ibuf[128]; @@ -1151,8 +1338,7 @@ next_header: case RTM_SETLINK: ifi = NLMSG_DATA(nlmsg); zlog_debug( - " ifinfomsg [family=%d type=(%d) %s " - "index=%d flags=0x%04x {%s}]", + " ifinfomsg [family=%d type=(%d) %s index=%d flags=0x%04x {%s}]", ifi->ifi_family, ifi->ifi_type, ifi_type2str(ifi->ifi_type), ifi->ifi_index, ifi->ifi_flags, @@ -1170,9 +1356,7 @@ next_header: case RTM_GETROUTE: rtm = NLMSG_DATA(nlmsg); zlog_debug( - " rtmsg [family=(%d) %s dstlen=%d srclen=%d tos=%d " - "table=%d protocol=(%d) %s scope=(%d) %s " - "type=(%d) %s flags=0x%04x {%s}]", + " rtmsg [family=(%d) %s dstlen=%d srclen=%d tos=%d table=%d protocol=(%d) %s scope=(%d) %s type=(%d) %s flags=0x%04x {%s}]", rtm->rtm_family, af_type2str(rtm->rtm_family), rtm->rtm_dst_len, rtm->rtm_src_len, rtm->rtm_tos, rtm->rtm_table, rtm->rtm_protocol, @@ -1188,8 +1372,7 @@ next_header: case RTM_DELNEIGH: ndm = NLMSG_DATA(nlmsg); zlog_debug( - " ndm [family=%d (%s) ifindex=%d state=0x%04x {%s} " - "flags=0x%04x {%s} type=%d (%s)]", + " ndm [family=%d (%s) ifindex=%d state=0x%04x {%s} flags=0x%04x {%s} type=%d (%s)]", ndm->ndm_family, af_type2str(ndm->ndm_family), ndm->ndm_ifindex, ndm->ndm_state, neigh_state2str(ndm->ndm_state, ibuf, sizeof(ibuf)), @@ -1200,12 +1383,24 @@ next_header: nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(*ndm))); break; + case RTM_NEWRULE: + case RTM_DELRULE: + frh = NLMSG_DATA(nlmsg); + zlog_debug( + " frh [family=%d (%s) dst_len=%d src_len=%d tos=%d table=%d res1=%d res2=%d action=%d (%s) flags=0x%x]", + frh->family, af_type2str(frh->family), frh->dst_len, + frh->src_len, frh->tos, frh->table, frh->res1, + frh->res2, frh->action, frh_action2str(frh->action), + frh->flags); + nlrule_dump(frh, nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(*frh))); + break; + + case RTM_NEWADDR: case RTM_DELADDR: ifa = NLMSG_DATA(nlmsg); zlog_debug( - " ifa [family=(%d) %s prefixlen=%d " - "flags=0x%04x {%s} scope=%d index=%u]", + " ifa [family=(%d) %s prefixlen=%d flags=0x%04x {%s} scope=%d index=%u]", ifa->ifa_family, af_type2str(ifa->ifa_family), ifa->ifa_prefixlen, ifa->ifa_flags, if_flags2str(ifa->ifa_flags, fbuf, sizeof(fbuf)), @@ -1218,8 +1413,7 @@ next_header: case RTM_GETNEXTHOP: nhm = NLMSG_DATA(nlmsg); zlog_debug( - " nhm [family=(%d) %s scope=(%d) %s " - "protocol=(%d) %s flags=0x%08x {%s}]", + " nhm [family=(%d) %s scope=(%d) %s protocol=(%d) %s flags=0x%08x {%s}]", nhm->nh_family, af_type2str(nhm->nh_family), nhm->nh_scope, rtm_scope2str(nhm->nh_scope), nhm->nh_protocol, rtm_protocol2str(nhm->nh_protocol), diff --git a/zebra/ioctl.c b/zebra/ioctl.c index 8b30eea9f1..9b6aaf1d85 100644 --- a/zebra/ioctl.c +++ b/zebra/ioctl.c @@ -410,11 +410,14 @@ int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx) void if_get_flags(struct interface *ifp) { int ret; - struct ifreq ifreq; + struct ifreq ifreqflags; + struct ifreq ifreqdata; - ifreq_set_name(&ifreq, ifp); + ifreq_set_name(&ifreqflags, ifp); + ifreq_set_name(&ifreqdata, ifp); - ret = vrf_if_ioctl(SIOCGIFFLAGS, (caddr_t)&ifreq, ifp->vrf->vrf_id); + ret = vrf_if_ioctl(SIOCGIFFLAGS, (caddr_t)&ifreqflags, + ifp->vrf->vrf_id); if (ret < 0) { flog_err_sys(EC_LIB_SYSTEM_CALL, "vrf_if_ioctl(SIOCGIFFLAGS %s) failed: %s", @@ -448,8 +451,8 @@ void if_get_flags(struct interface *ifp) struct if_data ifd = {.ifi_link_state = 0}; struct if_data *ifdata = &ifd; - ifreq.ifr_data = (caddr_t)ifdata; - ret = vrf_if_ioctl(SIOCGIFDATA, (caddr_t)&ifreq, ifp->vrf->vrf_id); + ifreqdata.ifr_data = (caddr_t)ifdata; + ret = vrf_if_ioctl(SIOCGIFDATA, (caddr_t)&ifreqdata, ifp->vrf->vrf_id); #endif if (ret == -1) @@ -459,12 +462,12 @@ void if_get_flags(struct interface *ifp) safe_strerror(errno)); else { if (ifdata->ifi_link_state >= LINK_STATE_UP) - SET_FLAG(ifreq.ifr_flags, IFF_RUNNING); + SET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING); else if (ifdata->ifi_link_state == LINK_STATE_UNKNOWN) /* BSD traditionally treats UNKNOWN as UP */ - SET_FLAG(ifreq.ifr_flags, IFF_RUNNING); + SET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING); else - UNSET_FLAG(ifreq.ifr_flags, IFF_RUNNING); + UNSET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING); } #elif defined(HAVE_BSD_LINK_DETECT) @@ -489,14 +492,14 @@ void if_get_flags(struct interface *ifp) ifp->name, safe_strerror(errno)); } else if (ifmr.ifm_status & IFM_AVALID) { /* media state is valid */ if (ifmr.ifm_status & IFM_ACTIVE) /* media is active */ - SET_FLAG(ifreq.ifr_flags, IFF_RUNNING); + SET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING); else - UNSET_FLAG(ifreq.ifr_flags, IFF_RUNNING); + UNSET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING); } #endif /* HAVE_BSD_LINK_DETECT */ out: - if_flags_update(ifp, (ifreq.ifr_flags & 0x0000ffff)); + if_flags_update(ifp, (ifreqflags.ifr_flags & 0x0000ffff)); } /* Set interface flags */ diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index d0c86a6bb0..84c15a2a92 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -159,7 +159,17 @@ extern struct zebra_privs_t zserv_privs; DEFINE_MTYPE_STATIC(ZEBRA, NL_BUF, "Zebra Netlink buffers"); -struct hash *nlsock_hash; +/* Hashtable and mutex to allow lookup of nlsock structs by socket/fd value. + * We have both the main and dplane pthreads using these structs, so we have + * to protect the hash with a lock. + */ +static struct hash *nlsock_hash; +pthread_mutex_t nlsock_mutex; + +/* Lock and unlock wrappers for nlsock hash */ +#define NLSOCK_LOCK() pthread_mutex_lock(&nlsock_mutex) +#define NLSOCK_UNLOCK() pthread_mutex_unlock(&nlsock_mutex) + size_t nl_batch_tx_bufsize; char *nl_batch_tx_buf; @@ -1201,7 +1211,7 @@ static int nl_batch_read_resp(struct nl_batch *bth) if (dplane_ctx_get_ns(ctx)->seq > seq) zlog_warn( - "%s:WARNING Recieved %u is less than any context on the queue ctx->seq %u", + "%s:WARNING Received %u is less than any context on the queue ctx->seq %u", __func__, seq, dplane_ctx_get_ns(ctx)->seq); } @@ -1513,11 +1523,31 @@ void kernel_update_multi(struct dplane_ctx_q *ctx_list) struct nlsock *kernel_netlink_nlsock_lookup(int sock) { - struct nlsock lookup; + struct nlsock lookup, *retval; lookup.sock = sock; - return hash_lookup(nlsock_hash, &lookup); + NLSOCK_LOCK(); + retval = hash_lookup(nlsock_hash, &lookup); + NLSOCK_UNLOCK(); + + return retval; +} + +/* Insert nlsock entry into hash */ +static void kernel_netlink_nlsock_insert(struct nlsock *nls) +{ + NLSOCK_LOCK(); + (void)hash_get(nlsock_hash, nls, hash_alloc_intern); + NLSOCK_UNLOCK(); +} + +/* Remove nlsock entry from hash */ +static void kernel_netlink_nlsock_remove(struct nlsock *nls) +{ + NLSOCK_LOCK(); + (void)hash_release(nlsock_hash, nls); + NLSOCK_UNLOCK(); } static uint32_t kernel_netlink_nlsock_key(const void *arg) @@ -1547,11 +1577,6 @@ void kernel_init(struct zebra_ns *zns) int one, ret; #endif - if (!nlsock_hash) - nlsock_hash = hash_create_size(8, kernel_netlink_nlsock_key, - kernel_netlink_nlsock_hash_equal, - "Netlink Socket Hash"); - /* * Initialize netlink sockets * @@ -1584,7 +1609,8 @@ void kernel_init(struct zebra_ns *zns) zns->netlink.name); exit(-1); } - (void)hash_get(nlsock_hash, &zns->netlink, hash_alloc_intern); + + kernel_netlink_nlsock_insert(&zns->netlink); snprintf(zns->netlink_cmd.name, sizeof(zns->netlink_cmd.name), "netlink-cmd (NS %u)", zns->ns_id); @@ -1594,7 +1620,8 @@ void kernel_init(struct zebra_ns *zns) zns->netlink_cmd.name); exit(-1); } - (void)hash_get(nlsock_hash, &zns->netlink_cmd, hash_alloc_intern); + + kernel_netlink_nlsock_insert(&zns->netlink_cmd); /* Outbound socket for dplane programming of the host OS. */ snprintf(zns->netlink_dplane_out.name, @@ -1606,8 +1633,8 @@ void kernel_init(struct zebra_ns *zns) zns->netlink_dplane_out.name); exit(-1); } - (void)hash_get(nlsock_hash, &zns->netlink_dplane_out, - hash_alloc_intern); + + kernel_netlink_nlsock_insert(&zns->netlink_dplane_out); /* Inbound socket for OS events coming to the dplane. */ snprintf(zns->netlink_dplane_in.name, @@ -1620,7 +1647,8 @@ void kernel_init(struct zebra_ns *zns) zns->netlink_dplane_in.name); exit(-1); } - (void)hash_get(nlsock_hash, &zns->netlink_dplane_in, hash_alloc_intern); + + kernel_netlink_nlsock_insert(&zns->netlink_dplane_in); /* * SOL_NETLINK is not available on all platforms yet @@ -1706,47 +1734,56 @@ void kernel_init(struct zebra_ns *zns) rt_netlink_init(); } +/* Helper to clean up an nlsock */ +static void kernel_nlsock_fini(struct nlsock *nls) +{ + if (nls && nls->sock >= 0) { + kernel_netlink_nlsock_remove(nls); + close(nls->sock); + nls->sock = -1; + XFREE(MTYPE_NL_BUF, nls->buf); + nls->buflen = 0; + } +} + void kernel_terminate(struct zebra_ns *zns, bool complete) { thread_cancel(&zns->t_netlink); - if (zns->netlink.sock >= 0) { - hash_release(nlsock_hash, &zns->netlink); - close(zns->netlink.sock); - zns->netlink.sock = -1; - XFREE(MTYPE_NL_BUF, zns->netlink.buf); - zns->netlink.buflen = 0; - } + kernel_nlsock_fini(&zns->netlink); - if (zns->netlink_cmd.sock >= 0) { - hash_release(nlsock_hash, &zns->netlink_cmd); - close(zns->netlink_cmd.sock); - zns->netlink_cmd.sock = -1; - XFREE(MTYPE_NL_BUF, zns->netlink_cmd.buf); - zns->netlink_cmd.buflen = 0; - } + kernel_nlsock_fini(&zns->netlink_cmd); - if (zns->netlink_dplane_in.sock >= 0) { - hash_release(nlsock_hash, &zns->netlink_dplane_in); - close(zns->netlink_dplane_in.sock); - zns->netlink_dplane_in.sock = -1; - XFREE(MTYPE_NL_BUF, zns->netlink_dplane_in.buf); - zns->netlink_dplane_in.buflen = 0; - } + kernel_nlsock_fini(&zns->netlink_dplane_in); /* During zebra shutdown, we need to leave the dataplane socket * around until all work is done. */ - if (complete) { - if (zns->netlink_dplane_out.sock >= 0) { - hash_release(nlsock_hash, &zns->netlink_dplane_out); - close(zns->netlink_dplane_out.sock); - zns->netlink_dplane_out.sock = -1; - XFREE(MTYPE_NL_BUF, zns->netlink_dplane_out.buf); - zns->netlink_dplane_out.buflen = 0; - } + if (complete) + kernel_nlsock_fini(&zns->netlink_dplane_out); +} - hash_free(nlsock_hash); - } +/* + * Global init for platform-/OS-specific things + */ +void kernel_router_init(void) +{ + /* Init nlsock hash and lock */ + pthread_mutex_init(&nlsock_mutex, NULL); + nlsock_hash = hash_create_size(8, kernel_netlink_nlsock_key, + kernel_netlink_nlsock_hash_equal, + "Netlink Socket Hash"); +} + +/* + * Global deinit for platform-/OS-specific things + */ +void kernel_router_terminate(void) +{ + pthread_mutex_destroy(&nlsock_mutex); + + hash_free(nlsock_hash); + nlsock_hash = NULL; } + #endif /* HAVE_NETLINK */ diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 3c9d203a0b..b9228072e5 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -1460,6 +1460,20 @@ void kernel_terminate(struct zebra_ns *zns, bool complete) } /* + * Global init for platform-/OS-specific things + */ +void kernel_router_init(void) +{ +} + +/* + * Global deinit for platform-/OS-specific things + */ +void kernel_router_terminate(void) +{ +} + +/* * Called by the dplane pthread to read incoming OS messages and dispatch them. */ int kernel_dplane_read(struct zebra_dplane_info *info) diff --git a/zebra/rt.h b/zebra/rt.h index 90148d2c0d..5e626928d9 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -78,6 +78,10 @@ extern int kernel_interface_set_master(struct interface *master, extern int mpls_kernel_init(void); +/* Global init and deinit for platform-/OS-specific things */ +void kernel_router_init(void); +void kernel_router_terminate(void); + extern uint32_t kernel_get_speed(struct interface *ifp, int *error); extern int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *mroute); diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h index 93c06e555b..0a79771708 100644 --- a/zebra/rt_netlink.h +++ b/zebra/rt_netlink.h @@ -134,6 +134,8 @@ const char *rtm_rta2str(int type); const char *neigh_rta2str(int type); const char *ifa_rta2str(int type); const char *nhm_rta2str(int type); +const char *frh_rta2str(int type); +const char *frh_action2str(uint8_t action); const char *nlmsg_flags2str(uint16_t flags, char *buf, size_t buflen); const char *if_flags2str(uint32_t flags, char *buf, size_t buflen); const char *rtm_flags2str(uint32_t flags, char *buf, size_t buflen); diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c index 92a3b9424b..6b4a7543cd 100644 --- a/zebra/zebra_router.c +++ b/zebra/zebra_router.c @@ -262,6 +262,9 @@ void zebra_router_terminate(void) #ifdef HAVE_SCRIPTING zebra_script_destroy(); #endif + + /* OS-specific deinit */ + kernel_router_terminate(); } bool zebra_router_notify_on_ack(void) @@ -307,4 +310,7 @@ void zebra_router_init(bool asic_offload, bool notify_on_ack) #ifdef HAVE_SCRIPTING zebra_script_init(); #endif + + /* OS-specific init */ + kernel_router_init(); } |
